Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp3716167imm; Mon, 18 Jun 2018 02:52:43 -0700 (PDT) X-Google-Smtp-Source: ADUXVKJ0mrEhDhuRjw5y+5aJ+VRNLlqK4LMFITproM4vy0mdvxEvPXJvb5TXq/asNXnpww1uJaDW X-Received: by 2002:a62:c809:: with SMTP id z9-v6mr12626712pff.5.1529315563850; Mon, 18 Jun 2018 02:52:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529315563; cv=none; d=google.com; s=arc-20160816; b=hzyQ2FgHx2ihwC905I6dvCyXqrix4NDbC+EgYZiLEG5aYjCgOo31SX5b0hMS889DU3 NGKDmdsaambFlFJuBl0LFtaXUEZKNZcVKhex2aY3pbYyU5+rM501UAkjRXKbBpv+o3Gv GaHenwhugwTeTx1HvRH0tmPHvbpFKxuYzXPQj1TZKqYj/0fhWSouqptLgYFO9Ra8O2Nj fhiFTgEeXQdcV/crjNp1QsCDl1+R/1Ee3IeRd2CzIuXhcS/wDhTIMTMIrATQSzsbnwdR VuJ3+sd6ZbX43CORRW7lx9nYCPfpSKQPPnEzTCVO7b5v6SfbU0dRv2pdEKbqVEcVWYwx Edow== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=34CRcMazzXrXilhJWYoj2jPFqwoPjk/lNa6SYbag+fo=; b=P7n6IIBOIcMBHywNt+ljg2fAJ55tx5kPgg+KXx5kPgJ4BxaKw2m28MQPVSRkV8eI8C tmJjXNQdU+h6BfDJYNtyaWJxp7u73cNUfbHU+DJn0KmbvTspqBwtrca7Jpvrp+buXfZe sqyELZMLyyVMQiGy4ipWEXXRAG9dQhxiF99ZuG6L4vS4a6BJQaK52bWR8W8xHLSLSeDa 4urm+uDVz1XS4Cy+V/QHQDpqUna7aO8PEgsdhXzAPLXXKOF2+kM/GjKpz27qQC/XDHLq 5E9ITA75AkOuL5YzeriroMKFfczvkwf+8SJil0977FkY+JA0wOmVgCR3JpQQN3LDVbbB qMtw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y65-v6si14454768pfi.195.2018.06.18.02.52.29; Mon, 18 Jun 2018 02:52:43 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935961AbeFRJvN (ORCPT + 99 others); Mon, 18 Jun 2018 05:51:13 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:55300 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933337AbeFRIVY (ORCPT ); Mon, 18 Jun 2018 04:21:24 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 637D8C7A; Mon, 18 Jun 2018 08:21:23 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Gianluca Borello , Alexei Starovoitov , Daniel Borkmann , Sasha Levin Subject: [PATCH 4.16 099/279] bpf, x64: fix JIT emission for dead code Date: Mon, 18 Jun 2018 10:11:24 +0200 Message-Id: <20180618080612.899041223@linuxfoundation.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180618080608.851973560@linuxfoundation.org> References: <20180618080608.851973560@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.16-stable review patch. If anyone has any objections, please let me know. ------------------ From: Gianluca Borello [ Upstream commit 1612a981b76688c598dc944bbfbe29a2b33e3973 ] Commit 2a5418a13fcf ("bpf: improve dead code sanitizing") replaced dead code with a series of ja-1 instructions, for safety. That made JIT compilation much more complex for some BPF programs. One instance of such programs is, for example: bool flag = false ... /* A bunch of other code */ ... if (flag) do_something() In some cases llvm is not able to remove at compile time the code for do_something(), so the generated BPF program ends up with a large amount of dead instructions. In one specific real life example, there are two series of ~500 and ~1000 dead instructions in the program. When the verifier replaces them with a series of ja-1 instructions, it causes an interesting behavior at JIT time. During the first pass, since all the instructions are estimated at 64 bytes, the ja-1 instructions end up being translated as 5 bytes JMP instructions (0xE9), since the jump offsets become increasingly large (> 127) as each instruction gets discovered to be 5 bytes instead of the estimated 64. Starting from the second pass, the first N instructions of the ja-1 sequence get translated into 2 bytes JMPs (0xEB) because the jump offsets become <= 127 this time. In particular, N is defined as roughly 127 / (5 - 2) ~= 42. So, each further pass will make the subsequent N JMP instructions shrink from 5 to 2 bytes, making the image shrink every time. This means that in order to have the entire program converge, there need to be, in the real example above, at least ~1000 / 42 ~= 24 passes just for translating the dead code. If we add this number to the passes needed to translate the other non dead code, it brings such program to 40+ passes, and JIT doesn't complete. Ultimately the userspace loader fails because such BPF program was supposed to be part of a prog array owner being JITed. While it is certainly possible to try to refactor such programs to help the compiler remove dead code, the behavior is not really intuitive and it puts further burden on the BPF developer who is not expecting such behavior. To make things worse, such programs are working just fine in all the kernel releases prior to the ja-1 fix. A possible approach to mitigate this behavior consists into noticing that for ja-1 instructions we don't really need to rely on the estimated size of the previous and current instructions, we know that a -1 BPF jump offset can be safely translated into a 0xEB instruction with a jump offset of -2. Such fix brings the BPF program in the previous example to complete again in ~9 passes. Fixes: 2a5418a13fcf ("bpf: improve dead code sanitizing") Signed-off-by: Gianluca Borello Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/net/bpf_jit_comp.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -992,7 +992,17 @@ emit_cond_jmp: /* convert BPF opcode to break; case BPF_JMP | BPF_JA: - jmp_offset = addrs[i + insn->off] - addrs[i]; + if (insn->off == -1) + /* -1 jmp instructions will always jump + * backwards two bytes. Explicitly handling + * this case avoids wasting too many passes + * when there are long sequences of replaced + * dead code. + */ + jmp_offset = -2; + else + jmp_offset = addrs[i + insn->off] - addrs[i]; + if (!jmp_offset) /* optimize out nop jumps */ break;