Received: by 2002:a25:1985:0:0:0:0:0 with SMTP id 127csp1240611ybz; Wed, 29 Apr 2020 17:55:39 -0700 (PDT) X-Google-Smtp-Source: APiQypLkhctne9L49vcGIIMdU0yRdE7fKRVck1mUr7FQSxe2H2b3o4Ac9Dzq8EjdbU8as9m1jcdC X-Received: by 2002:a05:6402:1a49:: with SMTP id bf9mr558022edb.189.1588208139759; Wed, 29 Apr 2020 17:55:39 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1588208139; cv=none; d=google.com; s=arc-20160816; b=Vdv8C4IvT4hyKbN8e1tlAbmNmv28mFmF5pl9+AtMiNxSEtVKDyQXwrcI+l6YBlIEzu gzR1j2gBWfk+ybKKhqurdf6u03eoulChXaH49wAa4WqYGvfpcyhUIPVovYywQ2Ii0JXC veuSlOP9czboZ/TDNcA5Ro90Q0wifOaZ668eKN3aN9TuSV9B5UrOjHKvJy1xWasyH78L ftUJ+b7Pa2ScyrfqF73eMl3kqRbdVU2aJnghArLyInwKWWXJyPfvxv4nkURFuNF7GVyn Z4xihv96eyWs/6kp//OtLW2vzwYph9YDRZ0G54yS/RngtIjdTtHM4P6NBuRTbkKQ4z1r R+NA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :dkim-signature; bh=2VzTJMG6uHW6Q2DV451ZYKmYi8OhZd8DBxFpPNX7pIs=; b=i6EvxOy1ez3jNN+YZr5q4BvxfYE816c7/uzfWAaygJxHceeg0BAQ2HpUvRWKGacwJ4 6TK6z6kwiakJj/BHBq38otS44wYipV2NvZLAvPWoeI+c1P8uE7EuSmoy2j/7CJy+dRvB HYxP6q30+jNwsAuF8isGCe88T8/WwOm8E5vA6yQl6H55uZHHr2wR1nFSDR5lI3//ss+y jf773mCFH39EqGMM9H+K7EoYwgo3QtPYjAtD64tS4IoIBFaM6K+FUzypIzgEs6P/0VUC WzuWLmOZRAwdRZowWCtJn9TD5j6mXuUGkU/YHcLOm/GKervhULkTdlo1AeLxWo6Y+Bcj 4ORQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@cs.washington.edu header.s=goo201206 header.b="dWCH6n/X"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=cs.washington.edu Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id h20si4977974ejb.126.2020.04.29.17.55.15; Wed, 29 Apr 2020 17:55:39 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@cs.washington.edu header.s=goo201206 header.b="dWCH6n/X"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=cs.washington.edu Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726378AbgD3Avx (ORCPT + 99 others); Wed, 29 Apr 2020 20:51:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46168 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726279AbgD3Avw (ORCPT ); Wed, 29 Apr 2020 20:51:52 -0400 Received: from mail-pf1-x441.google.com (mail-pf1-x441.google.com [IPv6:2607:f8b0:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 77857C035494 for ; Wed, 29 Apr 2020 17:51:52 -0700 (PDT) Received: by mail-pf1-x441.google.com with SMTP id v63so2013861pfb.10 for ; Wed, 29 Apr 2020 17:51:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cs.washington.edu; s=goo201206; h=from:to:cc:subject:date:message-id; bh=2VzTJMG6uHW6Q2DV451ZYKmYi8OhZd8DBxFpPNX7pIs=; b=dWCH6n/XQPm3+gB7yUXpLsA59ZzW6xb8HTHCoz+hnD5AWL/NrTe2YwF/Rx+k4yZJav 4rmmLQE1zVAvF7NhwMXcaxhnVPjF7So0Mrc52lz2O6edht1hrmT634+Wz2YOQSkE2QDj ih94XlipYqiwDaPL74SgN3ebI+mIKL3nAhY6s= 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; bh=2VzTJMG6uHW6Q2DV451ZYKmYi8OhZd8DBxFpPNX7pIs=; b=cC4lfzTuAFBHywKY/GAOdpNvuM/rYemvD7bB6/Cx5VDU9LS692yoz174fCELRwYYoX 5RdOMV8Ey7wgLlrZdzCUT21NHpoUPVeiUlZugASfjNk4Va4Su6G9xcFlLJboBeX2242F 1DUXALwmrkynHOpLNtCMHBeOKxPZo2SqYYXDUYU0qJuZT2kGAq27bPt1JXRzM5Q1M7Nz 0Ez1QXS5NMmdlhz4Tj2D72u1OcZ6Kx1gTpg33yNt8P+6pYeXQgVkRFeKuLN5FpYnkAlj IPet1QPZGOyEHp4AxrrNP35P4n3CiHTM+hoXewryooewUAGVFVYE3lVPlFTeAsG24G2V oGGg== X-Gm-Message-State: AGi0PubkZVtxz2/u3XwLvdIEKCpY/GiUyhZvfuLHubGTMb29W4EdaEfd tMBchQzPIm7Fk1YrLoRXossHwg== X-Received: by 2002:aa7:948f:: with SMTP id z15mr935807pfk.6.1588207911661; Wed, 29 Apr 2020 17:51:51 -0700 (PDT) Received: from localhost.localdomain (c-73-53-94-119.hsd1.wa.comcast.net. [73.53.94.119]) by smtp.gmail.com with ESMTPSA id o9sm347905pjp.4.2020.04.29.17.51.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2020 17:51:51 -0700 (PDT) From: Luke Nelson X-Google-Original-From: Luke Nelson To: bpf@vger.kernel.org Cc: Luke Nelson , Xi Wang , Alexei Starovoitov , Daniel Borkmann , Martin KaFai Lau , Song Liu , Yonghong Song , Andrii Nakryiko , John Fastabend , KP Singh , Paul Walmsley , Palmer Dabbelt , Albert Ou , netdev@vger.kernel.org, linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH bpf-next] bpf, riscv: Fix stack layout of JITed code on RV32 Date: Wed, 29 Apr 2020 17:51:27 -0700 Message-Id: <20200430005127.2205-1-luke.r.nels@gmail.com> X-Mailer: git-send-email 2.17.1 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch fixes issues with stackframe unwinding and alignment in the current stack layout for BPF programs on RV32. In the current layout, RV32 fp points to the JIT scratch registers, rather than to the callee-saved registers. This breaks stackframe unwinding, which expects fp to point just above the saved ra and fp registers. This patch fixes the issue by moving the callee-saved registers to be stored on the top of the stack, pointed to by fp. This satisfies the assumptions of stackframe unwinding. This patch also fixes an issue with the old layout that the stack was not aligned to 16 bytes. Stacktrace from JITed code using the old stack layout: [ 12.196249 ] [] walk_stackframe+0x0/0x96 Stacktrace using the new stack layout: [ 13.062888 ] [] walk_stackframe+0x0/0x96 [ 13.063028 ] [] show_stack+0x28/0x32 [ 13.063253 ] [] bpf_prog_82b916b2dfa00464+0x80/0x908 [ 13.063417 ] [] bpf_test_run+0x124/0x39a [ 13.063553 ] [] bpf_prog_test_run_skb+0x234/0x448 [ 13.063704 ] [] __do_sys_bpf+0x766/0x13b4 [ 13.063840 ] [] sys_bpf+0xc/0x14 [ 13.063961 ] [] ret_from_syscall+0x0/0x2 The new code is also simpler to understand and includes an ASCII diagram of the stack layout. Tested on riscv32 QEMU virt machine. Signed-off-by: Luke Nelson --- arch/riscv/net/bpf_jit_comp32.c | 98 ++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 33 deletions(-) diff --git a/arch/riscv/net/bpf_jit_comp32.c b/arch/riscv/net/bpf_jit_comp32.c index 11083d4d5f2d..b198eaa74456 100644 --- a/arch/riscv/net/bpf_jit_comp32.c +++ b/arch/riscv/net/bpf_jit_comp32.c @@ -13,8 +13,35 @@ #include #include "bpf_jit.h" +/* + * Stack layout during BPF program execution: + * + * high + * RV32 fp => +----------+ + * | saved ra | + * | saved fp | RV32 callee-saved registers + * | ... | + * +----------+ <= (fp - 4 * NR_SAVED_REGISTERS) + * | hi(R6) | + * | lo(R6) | + * | hi(R7) | JIT scratch space for BPF registers + * | lo(R7) | + * | ... | + * BPF_REG_FP => +----------+ <= (fp - 4 * NR_SAVED_REGISTERS + * | | - 4 * BPF_JIT_SCRATCH_REGS) + * | | + * | ... | BPF program stack + * | | + * RV32 sp => +----------+ + * | | + * | ... | Function call stack + * | | + * +----------+ + * low + */ + enum { - /* Stack layout - these are offsets from (top of stack - 4). */ + /* Stack layout - these are offsets from top of JIT scratch space. */ BPF_R6_HI, BPF_R6_LO, BPF_R7_HI, @@ -29,7 +56,11 @@ enum { BPF_JIT_SCRATCH_REGS, }; -#define STACK_OFFSET(k) (-4 - ((k) * 4)) +/* Number of callee-saved registers stored to stack: ra, fp, s1--s7. */ +#define NR_SAVED_REGISTERS 9 + +/* Offset from fp for BPF registers stored on stack. */ +#define STACK_OFFSET(k) (-4 - (4 * NR_SAVED_REGISTERS) - (4 * (k))) #define TMP_REG_1 (MAX_BPF_JIT_REG + 0) #define TMP_REG_2 (MAX_BPF_JIT_REG + 1) @@ -111,11 +142,9 @@ static void emit_imm64(const s8 *rd, s32 imm_hi, s32 imm_lo, static void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx) { - int stack_adjust = ctx->stack_size, store_offset = stack_adjust - 4; + int stack_adjust = ctx->stack_size; const s8 *r0 = bpf2rv32[BPF_REG_0]; - store_offset -= 4 * BPF_JIT_SCRATCH_REGS; - /* Set return value if not tail call. */ if (!is_tail_call) { emit(rv_addi(RV_REG_A0, lo(r0), 0), ctx); @@ -123,15 +152,15 @@ static void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx) } /* Restore callee-saved registers. */ - emit(rv_lw(RV_REG_RA, store_offset - 0, RV_REG_SP), ctx); - emit(rv_lw(RV_REG_FP, store_offset - 4, RV_REG_SP), ctx); - emit(rv_lw(RV_REG_S1, store_offset - 8, RV_REG_SP), ctx); - emit(rv_lw(RV_REG_S2, store_offset - 12, RV_REG_SP), ctx); - emit(rv_lw(RV_REG_S3, store_offset - 16, RV_REG_SP), ctx); - emit(rv_lw(RV_REG_S4, store_offset - 20, RV_REG_SP), ctx); - emit(rv_lw(RV_REG_S5, store_offset - 24, RV_REG_SP), ctx); - emit(rv_lw(RV_REG_S6, store_offset - 28, RV_REG_SP), ctx); - emit(rv_lw(RV_REG_S7, store_offset - 32, RV_REG_SP), ctx); + emit(rv_lw(RV_REG_RA, stack_adjust - 4, RV_REG_SP), ctx); + emit(rv_lw(RV_REG_FP, stack_adjust - 8, RV_REG_SP), ctx); + emit(rv_lw(RV_REG_S1, stack_adjust - 12, RV_REG_SP), ctx); + emit(rv_lw(RV_REG_S2, stack_adjust - 16, RV_REG_SP), ctx); + emit(rv_lw(RV_REG_S3, stack_adjust - 20, RV_REG_SP), ctx); + emit(rv_lw(RV_REG_S4, stack_adjust - 24, RV_REG_SP), ctx); + emit(rv_lw(RV_REG_S5, stack_adjust - 28, RV_REG_SP), ctx); + emit(rv_lw(RV_REG_S6, stack_adjust - 32, RV_REG_SP), ctx); + emit(rv_lw(RV_REG_S7, stack_adjust - 36, RV_REG_SP), ctx); emit(rv_addi(RV_REG_SP, RV_REG_SP, stack_adjust), ctx); @@ -1260,17 +1289,20 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx, void bpf_jit_build_prologue(struct rv_jit_context *ctx) { - /* Make space to save 9 registers: ra, fp, s1--s7. */ - int stack_adjust = 9 * sizeof(u32), store_offset, bpf_stack_adjust; const s8 *fp = bpf2rv32[BPF_REG_FP]; const s8 *r1 = bpf2rv32[BPF_REG_1]; - - bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, 16); + int stack_adjust = 0; + int bpf_stack_adjust = + round_up(ctx->prog->aux->stack_depth, STACK_ALIGN); + + /* Make space for callee-saved registers. */ + stack_adjust += NR_SAVED_REGISTERS * sizeof(u32); + /* Make space for BPF registers on stack. */ + stack_adjust += BPF_JIT_SCRATCH_REGS * sizeof(u32); + /* Make space for BPF stack. */ stack_adjust += bpf_stack_adjust; - - store_offset = stack_adjust - 4; - - stack_adjust += 4 * BPF_JIT_SCRATCH_REGS; + /* Round up for stack alignment. */ + stack_adjust = round_up(stack_adjust, STACK_ALIGN); /* * The first instruction sets the tail-call-counter (TCC) register. @@ -1281,24 +1313,24 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx) emit(rv_addi(RV_REG_SP, RV_REG_SP, -stack_adjust), ctx); /* Save callee-save registers. */ - emit(rv_sw(RV_REG_SP, store_offset - 0, RV_REG_RA), ctx); - emit(rv_sw(RV_REG_SP, store_offset - 4, RV_REG_FP), ctx); - emit(rv_sw(RV_REG_SP, store_offset - 8, RV_REG_S1), ctx); - emit(rv_sw(RV_REG_SP, store_offset - 12, RV_REG_S2), ctx); - emit(rv_sw(RV_REG_SP, store_offset - 16, RV_REG_S3), ctx); - emit(rv_sw(RV_REG_SP, store_offset - 20, RV_REG_S4), ctx); - emit(rv_sw(RV_REG_SP, store_offset - 24, RV_REG_S5), ctx); - emit(rv_sw(RV_REG_SP, store_offset - 28, RV_REG_S6), ctx); - emit(rv_sw(RV_REG_SP, store_offset - 32, RV_REG_S7), ctx); + emit(rv_sw(RV_REG_SP, stack_adjust - 4, RV_REG_RA), ctx); + emit(rv_sw(RV_REG_SP, stack_adjust - 8, RV_REG_FP), ctx); + emit(rv_sw(RV_REG_SP, stack_adjust - 12, RV_REG_S1), ctx); + emit(rv_sw(RV_REG_SP, stack_adjust - 16, RV_REG_S2), ctx); + emit(rv_sw(RV_REG_SP, stack_adjust - 20, RV_REG_S3), ctx); + emit(rv_sw(RV_REG_SP, stack_adjust - 24, RV_REG_S4), ctx); + emit(rv_sw(RV_REG_SP, stack_adjust - 28, RV_REG_S5), ctx); + emit(rv_sw(RV_REG_SP, stack_adjust - 32, RV_REG_S6), ctx); + emit(rv_sw(RV_REG_SP, stack_adjust - 36, RV_REG_S7), ctx); /* Set fp: used as the base address for stacked BPF registers. */ emit(rv_addi(RV_REG_FP, RV_REG_SP, stack_adjust), ctx); - /* Set up BPF stack pointer. */ + /* Set up BPF frame pointer. */ emit(rv_addi(lo(fp), RV_REG_SP, bpf_stack_adjust), ctx); emit(rv_addi(hi(fp), RV_REG_ZERO, 0), ctx); - /* Set up context pointer. */ + /* Set up BPF context pointer. */ emit(rv_addi(lo(r1), RV_REG_A0, 0), ctx); emit(rv_addi(hi(r1), RV_REG_ZERO, 0), ctx); -- 2.17.1