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.