|
Gary Lin |
4f5333 |
From: Jakub Kicinski <jakub.kicinski@netronome.com>
|
|
Gary Lin |
4f5333 |
Date: Mon, 9 Oct 2017 10:30:15 -0700
|
|
Gary Lin |
4f5333 |
Subject: bpf: write back the verifier log buffer as it gets filled
|
|
Gary Lin |
4f5333 |
Patch-mainline: v4.15-rc1
|
|
Gary Lin |
4f5333 |
Git-commit: a2a7d5701052542cd2260e7659b12443e0a74733
|
|
Gary Lin |
4f5333 |
References: bsc#1083647
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
Verifier log buffer can be quite large (up to 16MB currently).
|
|
Gary Lin |
4f5333 |
As Eric Dumazet points out if we allow multiple verification
|
|
Gary Lin |
4f5333 |
requests to proceed simultaneously, malicious user may use the
|
|
Gary Lin |
4f5333 |
verifier as a way of allocating large amounts of unswappable
|
|
Gary Lin |
4f5333 |
memory to OOM the host.
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
Switch to a strategy of allocating a smaller buffer (1024B)
|
|
Gary Lin |
4f5333 |
and writing it out into the user buffer after every print.
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
While at it remove the old BUG_ON().
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
This is in preparation of the global verifier lock removal.
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
|
|
Gary Lin |
4f5333 |
Reviewed-by: Simon Horman <simon.horman@netronome.com>
|
|
Gary Lin |
4f5333 |
Acked-by: Alexei Starovoitov <ast@kernel.org>
|
|
Gary Lin |
4f5333 |
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
|
|
Gary Lin |
4f5333 |
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
Gary Lin |
4f5333 |
Acked-by: Gary Lin <glin@suse.com>
|
|
Gary Lin |
4f5333 |
---
|
|
Gary Lin |
4f5333 |
include/linux/bpf_verifier.h | 4 +++-
|
|
Gary Lin |
4f5333 |
kernel/bpf/verifier.c | 41 +++++++++++++++++++----------------------
|
|
Gary Lin |
4f5333 |
2 files changed, 22 insertions(+), 23 deletions(-)
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
--- a/include/linux/bpf_verifier.h
|
|
Gary Lin |
4f5333 |
+++ b/include/linux/bpf_verifier.h
|
|
Gary Lin |
4f5333 |
@@ -115,9 +115,11 @@ struct bpf_insn_aux_data {
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
+#define BPF_VERIFIER_TMP_LOG_SIZE 1024
|
|
Gary Lin |
4f5333 |
+
|
|
Gary Lin |
4f5333 |
struct bpf_verifer_log {
|
|
Gary Lin |
4f5333 |
u32 level;
|
|
Gary Lin |
4f5333 |
- char *kbuf;
|
|
Gary Lin |
4f5333 |
+ char kbuf[BPF_VERIFIER_TMP_LOG_SIZE];
|
|
Gary Lin |
4f5333 |
char __user *ubuf;
|
|
Gary Lin |
4f5333 |
u32 len_used;
|
|
Gary Lin |
4f5333 |
u32 len_total;
|
|
Gary Lin |
4f5333 |
--- a/kernel/bpf/verifier.c
|
|
Gary Lin |
4f5333 |
+++ b/kernel/bpf/verifier.c
|
|
Gary Lin |
4f5333 |
@@ -165,15 +165,26 @@ static __printf(2, 3) void verbose(struc
|
|
Gary Lin |
4f5333 |
const char *fmt, ...)
|
|
Gary Lin |
4f5333 |
{
|
|
Gary Lin |
4f5333 |
struct bpf_verifer_log *log = &env->log;
|
|
Gary Lin |
4f5333 |
+ unsigned int n;
|
|
Gary Lin |
4f5333 |
va_list args;
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
- if (!log->level || bpf_verifier_log_full(log))
|
|
Gary Lin |
4f5333 |
+ if (!log->level || !log->ubuf || bpf_verifier_log_full(log))
|
|
Gary Lin |
4f5333 |
return;
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
va_start(args, fmt);
|
|
Gary Lin |
4f5333 |
- log->len_used += vscnprintf(log->kbuf + log->len_used,
|
|
Gary Lin |
4f5333 |
- log->len_total - log->len_used, fmt, args);
|
|
Gary Lin |
4f5333 |
+ n = vscnprintf(log->kbuf, BPF_VERIFIER_TMP_LOG_SIZE, fmt, args);
|
|
Gary Lin |
4f5333 |
va_end(args);
|
|
Gary Lin |
4f5333 |
+
|
|
Gary Lin |
4f5333 |
+ WARN_ONCE(n >= BPF_VERIFIER_TMP_LOG_SIZE - 1,
|
|
Gary Lin |
4f5333 |
+ "verifier log line truncated - local buffer too short\n");
|
|
Gary Lin |
4f5333 |
+
|
|
Gary Lin |
4f5333 |
+ n = min(log->len_total - log->len_used - 1, n);
|
|
Gary Lin |
4f5333 |
+ log->kbuf[n] = '\0';
|
|
Gary Lin |
4f5333 |
+
|
|
Gary Lin |
4f5333 |
+ if (!copy_to_user(log->ubuf + log->len_used, log->kbuf, n + 1))
|
|
Gary Lin |
4f5333 |
+ log->len_used += n;
|
|
Gary Lin |
4f5333 |
+ else
|
|
Gary Lin |
4f5333 |
+ log->ubuf = NULL;
|
|
Gary Lin |
4f5333 |
}
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
/* string representation of 'enum bpf_reg_type' */
|
|
Gary Lin |
4f5333 |
@@ -4153,11 +4164,6 @@ int bpf_check(struct bpf_prog **prog, un
|
|
Gary Lin |
4f5333 |
if (log->len_total < 128 || log->len_total > UINT_MAX >> 8 ||
|
|
Gary Lin |
4f5333 |
!log->level || !log->ubuf)
|
|
Gary Lin |
4f5333 |
goto err_unlock;
|
|
Gary Lin |
4f5333 |
-
|
|
Gary Lin |
4f5333 |
- ret = -ENOMEM;
|
|
Gary Lin |
4f5333 |
- log->kbuf = vmalloc(log->len_total);
|
|
Gary Lin |
4f5333 |
- if (!log->kbuf)
|
|
Gary Lin |
4f5333 |
- goto err_unlock;
|
|
Gary Lin |
4f5333 |
}
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT);
|
|
Gary Lin |
4f5333 |
@@ -4194,18 +4200,11 @@ skip_full_check:
|
|
Gary Lin |
4f5333 |
if (ret == 0)
|
|
Gary Lin |
4f5333 |
ret = fixup_bpf_calls(env);
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
- if (log->level && bpf_verifier_log_full(log)) {
|
|
Gary Lin |
4f5333 |
- BUG_ON(log->len_used >= log->len_total);
|
|
Gary Lin |
4f5333 |
- /* verifier log exceeded user supplied buffer */
|
|
Gary Lin |
4f5333 |
+ if (log->level && bpf_verifier_log_full(log))
|
|
Gary Lin |
4f5333 |
ret = -ENOSPC;
|
|
Gary Lin |
4f5333 |
- /* fall through to return what was recorded */
|
|
Gary Lin |
4f5333 |
- }
|
|
Gary Lin |
4f5333 |
-
|
|
Gary Lin |
4f5333 |
- /* copy verifier log back to user space including trailing zero */
|
|
Gary Lin |
4f5333 |
- if (log->level && copy_to_user(log->ubuf, log->kbuf,
|
|
Gary Lin |
4f5333 |
- log->len_used + 1) != 0) {
|
|
Gary Lin |
4f5333 |
+ if (log->level && !log->ubuf) {
|
|
Gary Lin |
4f5333 |
ret = -EFAULT;
|
|
Gary Lin |
4f5333 |
- goto free_log_buf;
|
|
Gary Lin |
4f5333 |
+ goto err_release_maps;
|
|
Gary Lin |
4f5333 |
}
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
if (ret == 0 && env->used_map_cnt) {
|
|
Gary Lin |
4f5333 |
@@ -4216,7 +4215,7 @@ skip_full_check:
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
if (!env->prog->aux->used_maps) {
|
|
Gary Lin |
4f5333 |
ret = -ENOMEM;
|
|
Gary Lin |
4f5333 |
- goto free_log_buf;
|
|
Gary Lin |
4f5333 |
+ goto err_release_maps;
|
|
Gary Lin |
4f5333 |
}
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
memcpy(env->prog->aux->used_maps, env->used_maps,
|
|
Gary Lin |
4f5333 |
@@ -4229,9 +4228,7 @@ skip_full_check:
|
|
Gary Lin |
4f5333 |
convert_pseudo_ld_imm64(env);
|
|
Gary Lin |
4f5333 |
}
|
|
Gary Lin |
4f5333 |
|
|
Gary Lin |
4f5333 |
-free_log_buf:
|
|
Gary Lin |
4f5333 |
- if (log->level)
|
|
Gary Lin |
4f5333 |
- vfree(log->kbuf);
|
|
Gary Lin |
4f5333 |
+err_release_maps:
|
|
Gary Lin |
4f5333 |
if (!env->prog->aux->used_maps)
|
|
Gary Lin |
4f5333 |
/* if we didn't copy map pointers into bpf_prog_info, release
|
|
Gary Lin |
4f5333 |
* them now. Otherwise free_bpf_prog_info() will release them.
|