From patchwork Wed Jan 23 06:45:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 1029694 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=netronome.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="gSPVEUD6"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43kwlx5Cmjz9s9G for ; Wed, 23 Jan 2019 17:45:49 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726682AbfAWGps (ORCPT ); Wed, 23 Jan 2019 01:45:48 -0500 Received: from mail-qt1-f194.google.com ([209.85.160.194]:41993 "EHLO mail-qt1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726326AbfAWGpr (ORCPT ); Wed, 23 Jan 2019 01:45:47 -0500 Received: by mail-qt1-f194.google.com with SMTP id d19so1193630qtq.9 for ; Tue, 22 Jan 2019 22:45:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netronome-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=4A89qKGqQaB/b6/hJaX2CpWY9pNmVV7Yt5gSCeGN1ks=; b=gSPVEUD6ixOWY8tg8bQDvGNmBWB2heN+J/2PGrNKD43WmCJnWdy3Vmu3OGYNTErChd zrXuA+N4KEDZ5qCdzSclVWU/e8b8uKEnYMWR05OhWgXtui3ojkL68FNF+YRDPqFmt25v UoHERlY1UGWLakWUG7XD9TAetsPCoqjF3uWluz7de+KljM2wCxGMl4lhwEyAyA6n53fF B5JW4EnsUJFrUErY7Js3UT4h+DxPEjvk+I0GBNEIz8TYCnpRK9pwpjJHyZqG7mJ8iOnc K+gys4yxA8cJICmbYEY9TLntxmZgMkU9/+HkuhVK3TExGczuv4jR/JdpU3ibHb+TUWCY tkKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=4A89qKGqQaB/b6/hJaX2CpWY9pNmVV7Yt5gSCeGN1ks=; b=FLbuQnuANsHGaJ/HQdWHbbyJuANoiKBvt0Oj/CNUM1NQP0SWy8N4zl4HUn5Y+Zm+cj yZ8aZ4ficrA48XGnvlVKWyIJ46E2/MfQJmpja9bsWWfkCJ/Ngf9OENqjbrptezH5wg49 s/erXhLfgR3RxEc3YUmhTcTGWkw9rDnPCzdbb9fV4cveSaOyPkca/MXeOe6bGSFaTvIJ LJffH8hjhGzwQ+x7NaAbhyOupxe3Oahb1pcvxKqvU6fOL+unKguk5FFny3dz881HelAg LtWumYMK4DWozf3Iu4ZX6CzjFC4/0ewVjj+E6leKGiyTirlVgFWpPzLTFs7ESdN9YSkx 9JfA== X-Gm-Message-State: AJcUukca6B38HQYy7R2CZjaofg6gNMbEu0rxaRKMa0qZtyv/ZWbP0lFN jq92AahUOFWQsfjh9EkgG7gC9w553W8= X-Google-Smtp-Source: ALg8bN6CF+CUiKcOpi05gGIooPYDk7InDAtP9PNM57JmLwf8zCVtt2U8SDEIuFuROoh3Vc7QYWz9zg== X-Received: by 2002:a0c:c192:: with SMTP id n18mr856967qvh.99.1548225946024; Tue, 22 Jan 2019 22:45:46 -0800 (PST) Received: from jkicinski-Precision-T1700.netronome.com ([66.60.152.14]) by smtp.gmail.com with ESMTPSA id k6sm80589046qtk.41.2019.01.22.22.45.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Jan 2019 22:45:45 -0800 (PST) From: Jakub Kicinski To: alexei.starovoitov@gmail.com, daniel@iogearbox.net Cc: yhs@fb.com, netdev@vger.kernel.org, oss-drivers@netronome.com, kafai@fb.com, Jakub Kicinski Subject: [PATCH bpf-next v5 02/12] bpf: verifier: hard wire branches to dead code Date: Tue, 22 Jan 2019 22:45:19 -0800 Message-Id: <20190123064529.13518-3-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20190123064529.13518-1-jakub.kicinski@netronome.com> References: <20190123064529.13518-1-jakub.kicinski@netronome.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Loading programs with dead code becomes more and more common, as people begin to patch constants at load time. Turn conditional jumps to unconditional ones, to avoid potential branch misprediction penalty. This optimization is enabled for privileged users only. For branches which just fall through we could just mark them as not seen and have dead code removal take care of them, but that seems less clean. v0.2: - don't call capable(CAP_SYS_ADMIN) twice (Jiong). v3: - fix GCC warning; Signed-off-by: Jakub Kicinski Acked-by: Yonghong Song --- kernel/bpf/verifier.c | 45 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ce87198ecd01..bf1f98e8beb6 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6458,6 +6458,40 @@ static void sanitize_dead_code(struct bpf_verifier_env *env) } } +static bool insn_is_cond_jump(u8 code) +{ + u8 op; + + if (BPF_CLASS(code) != BPF_JMP) + return false; + + op = BPF_OP(code); + return op != BPF_JA && op != BPF_EXIT && op != BPF_CALL; +} + +static void opt_hard_wire_dead_code_branches(struct bpf_verifier_env *env) +{ + struct bpf_insn_aux_data *aux_data = env->insn_aux_data; + struct bpf_insn ja = BPF_JMP_IMM(BPF_JA, 0, 0, 0); + struct bpf_insn *insn = env->prog->insnsi; + const int insn_cnt = env->prog->len; + int i; + + for (i = 0; i < insn_cnt; i++, insn++) { + if (!insn_is_cond_jump(insn->code)) + continue; + + if (!aux_data[i + 1].seen) + ja.off = insn->off; + else if (!aux_data[i + 1 + insn->off].seen) + ja.off = 0; + else + continue; + + memcpy(insn, &ja, sizeof(ja)); + } +} + /* convert load instructions that access fields of a context type into a * sequence of instructions that access fields of the underlying structure: * struct __sk_buff -> struct sk_buff @@ -7149,6 +7183,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, struct bpf_verifier_env *env; struct bpf_verifier_log *log; int ret = -EINVAL; + bool is_priv; /* no program is valid */ if (ARRAY_SIZE(bpf_verifier_ops) == 0) @@ -7195,6 +7230,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, if (attr->prog_flags & BPF_F_ANY_ALIGNMENT) env->strict_alignment = false; + is_priv = capable(CAP_SYS_ADMIN); + env->allow_ptr_leaks = is_priv; + ret = replace_map_fd_with_map_ptr(env); if (ret < 0) goto skip_full_check; @@ -7212,8 +7250,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, if (!env->explored_states) goto skip_full_check; - env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); - ret = check_subprogs(env); if (ret < 0) goto skip_full_check; @@ -7243,6 +7279,11 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, ret = check_max_stack_depth(env); /* instruction rewrites happen after this point */ + if (is_priv) { + if (ret == 0) + opt_hard_wire_dead_code_branches(env); + } + if (ret == 0) sanitize_dead_code(env);