|
@@ -165,15 +165,26 @@ static __printf(2, 3) void verbose(struct bpf_verifier_env *env,
|
|
|
const char *fmt, ...)
|
|
|
{
|
|
|
struct bpf_verifer_log *log = &env->log;
|
|
|
+ unsigned int n;
|
|
|
va_list args;
|
|
|
|
|
|
- if (!log->level || bpf_verifier_log_full(log))
|
|
|
+ if (!log->level || !log->ubuf || bpf_verifier_log_full(log))
|
|
|
return;
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
- log->len_used += vscnprintf(log->kbuf + log->len_used,
|
|
|
- log->len_total - log->len_used, fmt, args);
|
|
|
+ n = vscnprintf(log->kbuf, BPF_VERIFIER_TMP_LOG_SIZE, fmt, args);
|
|
|
va_end(args);
|
|
|
+
|
|
|
+ WARN_ONCE(n >= BPF_VERIFIER_TMP_LOG_SIZE - 1,
|
|
|
+ "verifier log line truncated - local buffer too short\n");
|
|
|
+
|
|
|
+ n = min(log->len_total - log->len_used - 1, n);
|
|
|
+ log->kbuf[n] = '\0';
|
|
|
+
|
|
|
+ if (!copy_to_user(log->ubuf + log->len_used, log->kbuf, n + 1))
|
|
|
+ log->len_used += n;
|
|
|
+ else
|
|
|
+ log->ubuf = NULL;
|
|
|
}
|
|
|
|
|
|
static bool type_is_pkt_pointer(enum bpf_reg_type type)
|
|
@@ -4263,11 +4274,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
|
|
|
if (log->len_total < 128 || log->len_total > UINT_MAX >> 8 ||
|
|
|
!log->level || !log->ubuf)
|
|
|
goto err_unlock;
|
|
|
-
|
|
|
- ret = -ENOMEM;
|
|
|
- log->kbuf = vmalloc(log->len_total);
|
|
|
- if (!log->kbuf)
|
|
|
- goto err_unlock;
|
|
|
}
|
|
|
|
|
|
env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT);
|
|
@@ -4304,18 +4310,11 @@ skip_full_check:
|
|
|
if (ret == 0)
|
|
|
ret = fixup_bpf_calls(env);
|
|
|
|
|
|
- if (log->level && bpf_verifier_log_full(log)) {
|
|
|
- BUG_ON(log->len_used >= log->len_total);
|
|
|
- /* verifier log exceeded user supplied buffer */
|
|
|
+ if (log->level && bpf_verifier_log_full(log))
|
|
|
ret = -ENOSPC;
|
|
|
- /* fall through to return what was recorded */
|
|
|
- }
|
|
|
-
|
|
|
- /* copy verifier log back to user space including trailing zero */
|
|
|
- if (log->level && copy_to_user(log->ubuf, log->kbuf,
|
|
|
- log->len_used + 1) != 0) {
|
|
|
+ if (log->level && !log->ubuf) {
|
|
|
ret = -EFAULT;
|
|
|
- goto free_log_buf;
|
|
|
+ goto err_release_maps;
|
|
|
}
|
|
|
|
|
|
if (ret == 0 && env->used_map_cnt) {
|
|
@@ -4326,7 +4325,7 @@ skip_full_check:
|
|
|
|
|
|
if (!env->prog->aux->used_maps) {
|
|
|
ret = -ENOMEM;
|
|
|
- goto free_log_buf;
|
|
|
+ goto err_release_maps;
|
|
|
}
|
|
|
|
|
|
memcpy(env->prog->aux->used_maps, env->used_maps,
|
|
@@ -4339,9 +4338,7 @@ skip_full_check:
|
|
|
convert_pseudo_ld_imm64(env);
|
|
|
}
|
|
|
|
|
|
-free_log_buf:
|
|
|
- if (log->level)
|
|
|
- vfree(log->kbuf);
|
|
|
+err_release_maps:
|
|
|
if (!env->prog->aux->used_maps)
|
|
|
/* if we didn't copy map pointers into bpf_prog_info, release
|
|
|
* them now. Otherwise free_bpf_prog_info() will release them.
|