netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jakub Kicinski <jakub.kicinski@netronome.com>
To: alexei.starovoitov@gmail.com, daniel@iogearbox.net
Cc: yhs@fb.com, netdev@vger.kernel.org, oss-drivers@netronome.com,
	Jakub Kicinski <jakub.kicinski@netronome.com>
Subject: [RFC bpf-next v3 02/12] bpf: verifier: hard wire branches to dead code
Date: Fri, 28 Dec 2018 19:09:13 -0800	[thread overview]
Message-ID: <20181229030923.4804-3-jakub.kicinski@netronome.com> (raw)
In-Reply-To: <20181229030923.4804-1-jakub.kicinski@netronome.com>

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).

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 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 71d86e3024ae..30e2cd399b4a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -6259,6 +6259,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
@@ -6899,6 +6933,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)
@@ -6945,6 +6980,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;
@@ -6962,8 +7000,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;
@@ -6993,6 +7029,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);
 
-- 
2.19.2

  parent reply	other threads:[~2018-12-29  3:09 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-29  3:09 [RFC bpf-next v3 00/12] bpf: dead code elimination Jakub Kicinski
2018-12-29  3:09 ` [RFC bpf-next v3 01/12] bpf: change parameters of call/branch offset adjustment Jakub Kicinski
2018-12-29  3:09 ` Jakub Kicinski [this message]
2018-12-29  3:09 ` [RFC bpf-next v3 03/12] bpf: verifier: remove dead code Jakub Kicinski
2018-12-30 22:02   ` Yonghong Song
2018-12-31 20:31     ` Jakub Kicinski
2018-12-31 21:41       ` Yonghong Song
2018-12-31 22:27         ` Jakub Kicinski
2018-12-29  3:09 ` [RFC bpf-next v3 04/12] bpf: verifier: remove unconditional branches by 0 Jakub Kicinski
2018-12-29  3:09 ` [RFC bpf-next v3 05/12] selftests: bpf: add tests for dead code removal Jakub Kicinski
2018-12-29  3:09 ` [RFC bpf-next v3 06/12] bpf: verifier: record original instruction index Jakub Kicinski
2018-12-29  3:09 ` [RFC bpf-next v3 07/12] bpf: notify offload JITs about optimizations Jakub Kicinski
2018-12-29  3:09 ` [RFC bpf-next v3 08/12] nfp: bpf: don't use instruction number for jump target Jakub Kicinski
2018-12-29  3:09 ` [RFC bpf-next v3 09/12] nfp: bpf: split up the skip flag Jakub Kicinski
2018-12-29  3:09 ` [RFC bpf-next v3 10/12] nfp: bpf: save original program length Jakub Kicinski
2018-12-29  3:09 ` [RFC bpf-next v3 11/12] nfp: bpf: support optimizing dead branches Jakub Kicinski
2018-12-29  3:09 ` [RFC bpf-next v3 12/12] nfp: bpf: support removing dead code Jakub Kicinski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181229030923.4804-3-jakub.kicinski@netronome.com \
    --to=jakub.kicinski@netronome.com \
    --cc=alexei.starovoitov@gmail.com \
    --cc=daniel@iogearbox.net \
    --cc=netdev@vger.kernel.org \
    --cc=oss-drivers@netronome.com \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).