mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Alexei Starovoitov says: ==================== The following pull-request contains BPF updates for your *net-next* tree. We've added 73 non-merge commits during the last 9 day(s) which contain a total of 79 files changed, 5275 insertions(+), 600 deletions(-). The main changes are: 1) Basic BTF validation in libbpf, from Andrii Nakryiko. 2) bpf_assert(), bpf_throw(), exceptions in bpf progs, from Kumar Kartikeya Dwivedi. 3) next_thread cleanups, from Oleg Nesterov. 4) Add mcpu=v4 support to arm32, from Puranjay Mohan. 5) Add support for __percpu pointers in bpf progs, from Yonghong Song. 6) Fix bpf tailcall interaction with bpf trampoline, from Leon Hwang. 7) Raise irq_work in bpf_mem_alloc while irqs are disabled to improve refill probabablity, from Hou Tao. Please consider pulling these changes from: git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git Thanks a lot! Also thanks to reporters, reviewers and testers of commits in this pull-request: Alan Maguire, Andrey Konovalov, Dave Marchevsky, "Eric W. Biederman", Jiri Olsa, Maciej Fijalkowski, Quentin Monnet, Russell King (Oracle), Song Liu, Stanislav Fomichev, Yonghong Song ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -113,7 +113,7 @@ Flags
|
||||
used by ``eth_get_headlen`` to estimate length of all headers for GRO.
|
||||
* ``BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL`` - tells BPF flow dissector to
|
||||
stop parsing as soon as it reaches IPv6 flow label; used by
|
||||
``___skb_get_hash`` and ``__skb_get_hash_symmetric`` to get flow hash.
|
||||
``___skb_get_hash`` to get flow hash.
|
||||
* ``BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP`` - tells BPF flow dissector to stop
|
||||
parsing as soon as it reaches encapsulated headers; used by routing
|
||||
infrastructure.
|
||||
|
||||
@@ -42,6 +42,19 @@ definitions:
|
||||
doc:
|
||||
This feature informs if netdev implements non-linear XDP buffer
|
||||
support in ndo_xdp_xmit callback.
|
||||
-
|
||||
type: flags
|
||||
name: xdp-rx-metadata
|
||||
render-max: true
|
||||
entries:
|
||||
-
|
||||
name: timestamp
|
||||
doc:
|
||||
Device is capable of exposing receive HW timestamp via bpf_xdp_metadata_rx_timestamp().
|
||||
-
|
||||
name: hash
|
||||
doc:
|
||||
Device is capable of exposing receive packet hash via bpf_xdp_metadata_rx_hash().
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
@@ -68,6 +81,13 @@ attribute-sets:
|
||||
type: u32
|
||||
checks:
|
||||
min: 1
|
||||
-
|
||||
name: xdp-rx-metadata-features
|
||||
doc: Bitmask of supported XDP receive metadata features.
|
||||
See Documentation/networking/xdp-rx-metadata.rst for more details.
|
||||
type: u64
|
||||
enum: xdp-rx-metadata
|
||||
enum-as-flags: true
|
||||
|
||||
operations:
|
||||
list:
|
||||
@@ -84,6 +104,7 @@ operations:
|
||||
- ifindex
|
||||
- xdp-features
|
||||
- xdp-zc-max-segs
|
||||
- xdp-rx-metadata-features
|
||||
dump:
|
||||
reply: *dev-all
|
||||
-
|
||||
|
||||
@@ -105,6 +105,13 @@ bpf_tail_call
|
||||
Adding programs that access metadata kfuncs to the ``BPF_MAP_TYPE_PROG_ARRAY``
|
||||
is currently not supported.
|
||||
|
||||
Supported Devices
|
||||
=================
|
||||
|
||||
It is possible to query which kfunc the particular netdev implements via
|
||||
netlink. See ``xdp-rx-metadata-features`` attribute set in
|
||||
``Documentation/netlink/specs/netdev.yaml``.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
|
||||
+3
-2
@@ -3596,9 +3596,10 @@ F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
|
||||
F: drivers/iio/accel/bma400*
|
||||
|
||||
BPF JIT for ARM
|
||||
M: Shubham Bansal <illusionist.neo@gmail.com>
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
M: Puranjay Mohan <puranjay12@gmail.com>
|
||||
L: bpf@vger.kernel.org
|
||||
S: Odd Fixes
|
||||
S: Maintained
|
||||
F: arch/arm/net/
|
||||
|
||||
BPF JIT for ARM64
|
||||
|
||||
+260
-20
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* Just-In-Time compiler for eBPF filters on 32bit ARM
|
||||
*
|
||||
* Copyright (c) 2023 Puranjay Mohan <puranjay12@gmail.com>
|
||||
* Copyright (c) 2017 Shubham Bansal <illusionist.neo@gmail.com>
|
||||
* Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com>
|
||||
*/
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/math64.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/hwcap.h>
|
||||
@@ -228,6 +230,44 @@ static u32 jit_mod32(u32 dividend, u32 divisor)
|
||||
return dividend % divisor;
|
||||
}
|
||||
|
||||
static s32 jit_sdiv32(s32 dividend, s32 divisor)
|
||||
{
|
||||
return dividend / divisor;
|
||||
}
|
||||
|
||||
static s32 jit_smod32(s32 dividend, s32 divisor)
|
||||
{
|
||||
return dividend % divisor;
|
||||
}
|
||||
|
||||
/* Wrappers for 64-bit div/mod */
|
||||
static u64 jit_udiv64(u64 dividend, u64 divisor)
|
||||
{
|
||||
return div64_u64(dividend, divisor);
|
||||
}
|
||||
|
||||
static u64 jit_mod64(u64 dividend, u64 divisor)
|
||||
{
|
||||
u64 rem;
|
||||
|
||||
div64_u64_rem(dividend, divisor, &rem);
|
||||
return rem;
|
||||
}
|
||||
|
||||
static s64 jit_sdiv64(s64 dividend, s64 divisor)
|
||||
{
|
||||
return div64_s64(dividend, divisor);
|
||||
}
|
||||
|
||||
static s64 jit_smod64(s64 dividend, s64 divisor)
|
||||
{
|
||||
u64 q;
|
||||
|
||||
q = div64_s64(dividend, divisor);
|
||||
|
||||
return dividend - q * divisor;
|
||||
}
|
||||
|
||||
static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
|
||||
{
|
||||
inst |= (cond << 28);
|
||||
@@ -333,6 +373,9 @@ static u32 arm_bpf_ldst_imm8(u32 op, u8 rt, u8 rn, s16 imm8)
|
||||
#define ARM_LDRD_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_LDRD_I, rt, rn, off)
|
||||
#define ARM_LDRH_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_LDRH_I, rt, rn, off)
|
||||
|
||||
#define ARM_LDRSH_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_LDRSH_I, rt, rn, off)
|
||||
#define ARM_LDRSB_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_LDRSB_I, rt, rn, off)
|
||||
|
||||
#define ARM_STR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_STR_I, rt, rn, off)
|
||||
#define ARM_STRB_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_STRB_I, rt, rn, off)
|
||||
#define ARM_STRD_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_STRD_I, rt, rn, off)
|
||||
@@ -474,17 +517,18 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
|
||||
return to - from - 2;
|
||||
}
|
||||
|
||||
static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
|
||||
static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op, u8 sign)
|
||||
{
|
||||
const int exclude_mask = BIT(ARM_R0) | BIT(ARM_R1);
|
||||
const s8 *tmp = bpf2a32[TMP_REG_1];
|
||||
u32 dst;
|
||||
|
||||
#if __LINUX_ARM_ARCH__ == 7
|
||||
if (elf_hwcap & HWCAP_IDIVA) {
|
||||
if (op == BPF_DIV)
|
||||
emit(ARM_UDIV(rd, rm, rn), ctx);
|
||||
else {
|
||||
emit(ARM_UDIV(ARM_IP, rm, rn), ctx);
|
||||
if (op == BPF_DIV) {
|
||||
emit(sign ? ARM_SDIV(rd, rm, rn) : ARM_UDIV(rd, rm, rn), ctx);
|
||||
} else {
|
||||
emit(sign ? ARM_SDIV(ARM_IP, rm, rn) : ARM_UDIV(ARM_IP, rm, rn), ctx);
|
||||
emit(ARM_MLS(rd, rn, ARM_IP, rm), ctx);
|
||||
}
|
||||
return;
|
||||
@@ -512,8 +556,19 @@ static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
|
||||
emit(ARM_PUSH(CALLER_MASK & ~exclude_mask), ctx);
|
||||
|
||||
/* Call appropriate function */
|
||||
emit_mov_i(ARM_IP, op == BPF_DIV ?
|
||||
(u32)jit_udiv32 : (u32)jit_mod32, ctx);
|
||||
if (sign) {
|
||||
if (op == BPF_DIV)
|
||||
dst = (u32)jit_sdiv32;
|
||||
else
|
||||
dst = (u32)jit_smod32;
|
||||
} else {
|
||||
if (op == BPF_DIV)
|
||||
dst = (u32)jit_udiv32;
|
||||
else
|
||||
dst = (u32)jit_mod32;
|
||||
}
|
||||
|
||||
emit_mov_i(ARM_IP, dst, ctx);
|
||||
emit_blx_r(ARM_IP, ctx);
|
||||
|
||||
/* Restore caller-saved registers from stack */
|
||||
@@ -530,6 +585,78 @@ static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
|
||||
emit(ARM_MOV_R(ARM_R0, tmp[1]), ctx);
|
||||
}
|
||||
|
||||
static inline void emit_udivmod64(const s8 *rd, const s8 *rm, const s8 *rn, struct jit_ctx *ctx,
|
||||
u8 op, u8 sign)
|
||||
{
|
||||
u32 dst;
|
||||
|
||||
/* Push caller-saved registers on stack */
|
||||
emit(ARM_PUSH(CALLER_MASK), ctx);
|
||||
|
||||
/*
|
||||
* As we are implementing 64-bit div/mod as function calls, We need to put the dividend in
|
||||
* R0-R1 and the divisor in R2-R3. As we have already pushed these registers on the stack,
|
||||
* we can recover them later after returning from the function call.
|
||||
*/
|
||||
if (rm[1] != ARM_R0 || rn[1] != ARM_R2) {
|
||||
/*
|
||||
* Move Rm to {R1, R0} if it is not already there.
|
||||
*/
|
||||
if (rm[1] != ARM_R0) {
|
||||
if (rn[1] == ARM_R0)
|
||||
emit(ARM_PUSH(BIT(ARM_R0) | BIT(ARM_R1)), ctx);
|
||||
emit(ARM_MOV_R(ARM_R1, rm[0]), ctx);
|
||||
emit(ARM_MOV_R(ARM_R0, rm[1]), ctx);
|
||||
if (rn[1] == ARM_R0) {
|
||||
emit(ARM_POP(BIT(ARM_R2) | BIT(ARM_R3)), ctx);
|
||||
goto cont;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Move Rn to {R3, R2} if it is not already there.
|
||||
*/
|
||||
if (rn[1] != ARM_R2) {
|
||||
emit(ARM_MOV_R(ARM_R3, rn[0]), ctx);
|
||||
emit(ARM_MOV_R(ARM_R2, rn[1]), ctx);
|
||||
}
|
||||
}
|
||||
|
||||
cont:
|
||||
|
||||
/* Call appropriate function */
|
||||
if (sign) {
|
||||
if (op == BPF_DIV)
|
||||
dst = (u32)jit_sdiv64;
|
||||
else
|
||||
dst = (u32)jit_smod64;
|
||||
} else {
|
||||
if (op == BPF_DIV)
|
||||
dst = (u32)jit_udiv64;
|
||||
else
|
||||
dst = (u32)jit_mod64;
|
||||
}
|
||||
|
||||
emit_mov_i(ARM_IP, dst, ctx);
|
||||
emit_blx_r(ARM_IP, ctx);
|
||||
|
||||
/* Save return value */
|
||||
if (rd[1] != ARM_R0) {
|
||||
emit(ARM_MOV_R(rd[0], ARM_R1), ctx);
|
||||
emit(ARM_MOV_R(rd[1], ARM_R0), ctx);
|
||||
}
|
||||
|
||||
/* Recover {R3, R2} and {R1, R0} from stack if they are not Rd */
|
||||
if (rd[1] != ARM_R0 && rd[1] != ARM_R2) {
|
||||
emit(ARM_POP(CALLER_MASK), ctx);
|
||||
} else if (rd[1] != ARM_R0) {
|
||||
emit(ARM_POP(BIT(ARM_R0) | BIT(ARM_R1)), ctx);
|
||||
emit(ARM_ADD_I(ARM_SP, ARM_SP, 8), ctx);
|
||||
} else {
|
||||
emit(ARM_ADD_I(ARM_SP, ARM_SP, 8), ctx);
|
||||
emit(ARM_POP(BIT(ARM_R2) | BIT(ARM_R3)), ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Is the translated BPF register on stack? */
|
||||
static bool is_stacked(s8 reg)
|
||||
{
|
||||
@@ -744,12 +871,16 @@ static inline void emit_a32_alu_r64(const bool is64, const s8 dst[],
|
||||
}
|
||||
|
||||
/* dst = src (4 bytes)*/
|
||||
static inline void emit_a32_mov_r(const s8 dst, const s8 src,
|
||||
static inline void emit_a32_mov_r(const s8 dst, const s8 src, const u8 off,
|
||||
struct jit_ctx *ctx) {
|
||||
const s8 *tmp = bpf2a32[TMP_REG_1];
|
||||
s8 rt;
|
||||
|
||||
rt = arm_bpf_get_reg32(src, tmp[0], ctx);
|
||||
if (off && off != 32) {
|
||||
emit(ARM_LSL_I(rt, rt, 32 - off), ctx);
|
||||
emit(ARM_ASR_I(rt, rt, 32 - off), ctx);
|
||||
}
|
||||
arm_bpf_put_reg32(dst, rt, ctx);
|
||||
}
|
||||
|
||||
@@ -758,15 +889,15 @@ static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
|
||||
const s8 src[],
|
||||
struct jit_ctx *ctx) {
|
||||
if (!is64) {
|
||||
emit_a32_mov_r(dst_lo, src_lo, ctx);
|
||||
emit_a32_mov_r(dst_lo, src_lo, 0, ctx);
|
||||
if (!ctx->prog->aux->verifier_zext)
|
||||
/* Zero out high 4 bytes */
|
||||
emit_a32_mov_i(dst_hi, 0, ctx);
|
||||
} else if (__LINUX_ARM_ARCH__ < 6 &&
|
||||
ctx->cpu_architecture < CPU_ARCH_ARMv5TE) {
|
||||
/* complete 8 byte move */
|
||||
emit_a32_mov_r(dst_lo, src_lo, ctx);
|
||||
emit_a32_mov_r(dst_hi, src_hi, ctx);
|
||||
emit_a32_mov_r(dst_lo, src_lo, 0, ctx);
|
||||
emit_a32_mov_r(dst_hi, src_hi, 0, ctx);
|
||||
} else if (is_stacked(src_lo) && is_stacked(dst_lo)) {
|
||||
const u8 *tmp = bpf2a32[TMP_REG_1];
|
||||
|
||||
@@ -782,6 +913,24 @@ static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
|
||||
}
|
||||
}
|
||||
|
||||
/* dst = (signed)src */
|
||||
static inline void emit_a32_movsx_r64(const bool is64, const u8 off, const s8 dst[], const s8 src[],
|
||||
struct jit_ctx *ctx) {
|
||||
const s8 *tmp = bpf2a32[TMP_REG_1];
|
||||
const s8 *rt;
|
||||
|
||||
rt = arm_bpf_get_reg64(dst, tmp, ctx);
|
||||
|
||||
emit_a32_mov_r(dst_lo, src_lo, off, ctx);
|
||||
if (!is64) {
|
||||
if (!ctx->prog->aux->verifier_zext)
|
||||
/* Zero out high 4 bytes */
|
||||
emit_a32_mov_i(dst_hi, 0, ctx);
|
||||
} else {
|
||||
emit(ARM_ASR_I(rt[0], rt[1], 31), ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Shift operations */
|
||||
static inline void emit_a32_alu_i(const s8 dst, const u32 val,
|
||||
struct jit_ctx *ctx, const u8 op) {
|
||||
@@ -1026,6 +1175,24 @@ static bool is_ldst_imm(s16 off, const u8 size)
|
||||
return -off_max <= off && off <= off_max;
|
||||
}
|
||||
|
||||
static bool is_ldst_imm8(s16 off, const u8 size)
|
||||
{
|
||||
s16 off_max = 0;
|
||||
|
||||
switch (size) {
|
||||
case BPF_B:
|
||||
off_max = 0xff;
|
||||
break;
|
||||
case BPF_W:
|
||||
off_max = 0xfff;
|
||||
break;
|
||||
case BPF_H:
|
||||
off_max = 0xff;
|
||||
break;
|
||||
}
|
||||
return -off_max <= off && off <= off_max;
|
||||
}
|
||||
|
||||
/* *(size *)(dst + off) = src */
|
||||
static inline void emit_str_r(const s8 dst, const s8 src[],
|
||||
s16 off, struct jit_ctx *ctx, const u8 sz){
|
||||
@@ -1105,6 +1272,50 @@ static inline void emit_ldx_r(const s8 dst[], const s8 src,
|
||||
arm_bpf_put_reg64(dst, rd, ctx);
|
||||
}
|
||||
|
||||
/* dst = *(signed size*)(src + off) */
|
||||
static inline void emit_ldsx_r(const s8 dst[], const s8 src,
|
||||
s16 off, struct jit_ctx *ctx, const u8 sz){
|
||||
const s8 *tmp = bpf2a32[TMP_REG_1];
|
||||
const s8 *rd = is_stacked(dst_lo) ? tmp : dst;
|
||||
s8 rm = src;
|
||||
int add_off;
|
||||
|
||||
if (!is_ldst_imm8(off, sz)) {
|
||||
/*
|
||||
* offset does not fit in the load/store immediate,
|
||||
* construct an ADD instruction to apply the offset.
|
||||
*/
|
||||
add_off = imm8m(off);
|
||||
if (add_off > 0) {
|
||||
emit(ARM_ADD_I(tmp[0], src, add_off), ctx);
|
||||
rm = tmp[0];
|
||||
} else {
|
||||
emit_a32_mov_i(tmp[0], off, ctx);
|
||||
emit(ARM_ADD_R(tmp[0], tmp[0], src), ctx);
|
||||
rm = tmp[0];
|
||||
}
|
||||
off = 0;
|
||||
}
|
||||
|
||||
switch (sz) {
|
||||
case BPF_B:
|
||||
/* Load a Byte with sign extension*/
|
||||
emit(ARM_LDRSB_I(rd[1], rm, off), ctx);
|
||||
break;
|
||||
case BPF_H:
|
||||
/* Load a HalfWord with sign extension*/
|
||||
emit(ARM_LDRSH_I(rd[1], rm, off), ctx);
|
||||
break;
|
||||
case BPF_W:
|
||||
/* Load a Word*/
|
||||
emit(ARM_LDR_I(rd[1], rm, off), ctx);
|
||||
break;
|
||||
}
|
||||
/* Carry the sign extension to upper 32 bits */
|
||||
emit(ARM_ASR_I(rd[0], rd[1], 31), ctx);
|
||||
arm_bpf_put_reg64(dst, rd, ctx);
|
||||
}
|
||||
|
||||
/* Arithmatic Operation */
|
||||
static inline void emit_ar_r(const u8 rd, const u8 rt, const u8 rm,
|
||||
const u8 rn, struct jit_ctx *ctx, u8 op,
|
||||
@@ -1385,7 +1596,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
emit_a32_mov_i(dst_hi, 0, ctx);
|
||||
break;
|
||||
}
|
||||
emit_a32_mov_r64(is64, dst, src, ctx);
|
||||
if (insn->off)
|
||||
emit_a32_movsx_r64(is64, insn->off, dst, src, ctx);
|
||||
else
|
||||
emit_a32_mov_r64(is64, dst, src, ctx);
|
||||
break;
|
||||
case BPF_K:
|
||||
/* Sign-extend immediate value to destination reg */
|
||||
@@ -1461,7 +1675,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
rt = src_lo;
|
||||
break;
|
||||
}
|
||||
emit_udivmod(rd_lo, rd_lo, rt, ctx, BPF_OP(code));
|
||||
emit_udivmod(rd_lo, rd_lo, rt, ctx, BPF_OP(code), off);
|
||||
arm_bpf_put_reg32(dst_lo, rd_lo, ctx);
|
||||
if (!ctx->prog->aux->verifier_zext)
|
||||
emit_a32_mov_i(dst_hi, 0, ctx);
|
||||
@@ -1470,7 +1684,19 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
case BPF_ALU64 | BPF_DIV | BPF_X:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_K:
|
||||
case BPF_ALU64 | BPF_MOD | BPF_X:
|
||||
goto notyet;
|
||||
rd = arm_bpf_get_reg64(dst, tmp2, ctx);
|
||||
switch (BPF_SRC(code)) {
|
||||
case BPF_X:
|
||||
rs = arm_bpf_get_reg64(src, tmp, ctx);
|
||||
break;
|
||||
case BPF_K:
|
||||
rs = tmp;
|
||||
emit_a32_mov_se_i64(is64, rs, imm, ctx);
|
||||
break;
|
||||
}
|
||||
emit_udivmod64(rd, rd, rs, ctx, BPF_OP(code), off);
|
||||
arm_bpf_put_reg64(dst, rd, ctx);
|
||||
break;
|
||||
/* dst = dst << imm */
|
||||
/* dst = dst >> imm */
|
||||
/* dst = dst >> imm (signed) */
|
||||
@@ -1545,10 +1771,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
|
||||
break;
|
||||
/* dst = htole(dst) */
|
||||
/* dst = htobe(dst) */
|
||||
case BPF_ALU | BPF_END | BPF_FROM_LE:
|
||||
case BPF_ALU | BPF_END | BPF_FROM_BE:
|
||||
case BPF_ALU | BPF_END | BPF_FROM_LE: /* also BPF_TO_LE */
|
||||
case BPF_ALU | BPF_END | BPF_FROM_BE: /* also BPF_TO_BE */
|
||||
/* dst = bswap(dst) */
|
||||
case BPF_ALU64 | BPF_END | BPF_FROM_LE: /* also BPF_TO_LE */
|
||||
rd = arm_bpf_get_reg64(dst, tmp, ctx);
|
||||
if (BPF_SRC(code) == BPF_FROM_LE)
|
||||
if (BPF_SRC(code) == BPF_FROM_LE && BPF_CLASS(code) != BPF_ALU64)
|
||||
goto emit_bswap_uxt;
|
||||
switch (imm) {
|
||||
case 16:
|
||||
@@ -1603,8 +1831,15 @@ exit:
|
||||
case BPF_LDX | BPF_MEM | BPF_H:
|
||||
case BPF_LDX | BPF_MEM | BPF_B:
|
||||
case BPF_LDX | BPF_MEM | BPF_DW:
|
||||
/* LDSX: dst = *(signed size *)(src + off) */
|
||||
case BPF_LDX | BPF_MEMSX | BPF_B:
|
||||
case BPF_LDX | BPF_MEMSX | BPF_H:
|
||||
case BPF_LDX | BPF_MEMSX | BPF_W:
|
||||
rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx);
|
||||
emit_ldx_r(dst, rn, off, ctx, BPF_SIZE(code));
|
||||
if (BPF_MODE(insn->code) == BPF_MEMSX)
|
||||
emit_ldsx_r(dst, rn, off, ctx, BPF_SIZE(code));
|
||||
else
|
||||
emit_ldx_r(dst, rn, off, ctx, BPF_SIZE(code));
|
||||
break;
|
||||
/* speculation barrier */
|
||||
case BPF_ST | BPF_NOSPEC:
|
||||
@@ -1761,10 +1996,15 @@ go_jmp:
|
||||
break;
|
||||
/* JMP OFF */
|
||||
case BPF_JMP | BPF_JA:
|
||||
case BPF_JMP32 | BPF_JA:
|
||||
{
|
||||
if (off == 0)
|
||||
if (BPF_CLASS(code) == BPF_JMP32 && imm != 0)
|
||||
jmp_offset = bpf2a32_offset(i + imm, i, ctx);
|
||||
else if (BPF_CLASS(code) == BPF_JMP && off != 0)
|
||||
jmp_offset = bpf2a32_offset(i + off, i, ctx);
|
||||
else
|
||||
break;
|
||||
jmp_offset = bpf2a32_offset(i+off, i, ctx);
|
||||
|
||||
check_imm24(jmp_offset);
|
||||
emit(ARM_B(jmp_offset), ctx);
|
||||
break;
|
||||
|
||||
@@ -79,9 +79,11 @@
|
||||
#define ARM_INST_LDST__IMM12 0x00000fff
|
||||
#define ARM_INST_LDRB_I 0x05500000
|
||||
#define ARM_INST_LDRB_R 0x07d00000
|
||||
#define ARM_INST_LDRSB_I 0x015000d0
|
||||
#define ARM_INST_LDRD_I 0x014000d0
|
||||
#define ARM_INST_LDRH_I 0x015000b0
|
||||
#define ARM_INST_LDRH_R 0x019000b0
|
||||
#define ARM_INST_LDRSH_I 0x015000f0
|
||||
#define ARM_INST_LDR_I 0x05100000
|
||||
#define ARM_INST_LDR_R 0x07900000
|
||||
|
||||
@@ -137,6 +139,7 @@
|
||||
#define ARM_INST_TST_I 0x03100000
|
||||
|
||||
#define ARM_INST_UDIV 0x0730f010
|
||||
#define ARM_INST_SDIV 0x0710f010
|
||||
|
||||
#define ARM_INST_UMULL 0x00800090
|
||||
|
||||
@@ -265,6 +268,7 @@
|
||||
#define ARM_TST_I(rn, imm) _AL3_I(ARM_INST_TST, 0, rn, imm)
|
||||
|
||||
#define ARM_UDIV(rd, rn, rm) (ARM_INST_UDIV | (rd) << 16 | (rn) | (rm) << 8)
|
||||
#define ARM_SDIV(rd, rn, rm) (ARM_INST_SDIV | (rd) << 16 | (rn) | (rm) << 8)
|
||||
|
||||
#define ARM_UMULL(rd_lo, rd_hi, rn, rm) (ARM_INST_UMULL | (rd_hi) << 16 \
|
||||
| (rd_lo) << 12 | (rm) << 8 | rn)
|
||||
|
||||
@@ -288,7 +288,7 @@ static bool is_lsi_offset(int offset, int scale)
|
||||
static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
|
||||
{
|
||||
const struct bpf_prog *prog = ctx->prog;
|
||||
const bool is_main_prog = prog->aux->func_idx == 0;
|
||||
const bool is_main_prog = !bpf_is_subprog(prog);
|
||||
const u8 r6 = bpf2a64[BPF_REG_6];
|
||||
const u8 r7 = bpf2a64[BPF_REG_7];
|
||||
const u8 r8 = bpf2a64[BPF_REG_8];
|
||||
|
||||
@@ -556,7 +556,7 @@ static void bpf_jit_prologue(struct bpf_jit *jit, struct bpf_prog *fp,
|
||||
EMIT6_PCREL_RILC(0xc0040000, 0, jit->prologue_plt);
|
||||
jit->prologue_plt_ret = jit->prg;
|
||||
|
||||
if (fp->aux->func_idx == 0) {
|
||||
if (!bpf_is_subprog(fp)) {
|
||||
/* Initialize the tail call counter in the main program. */
|
||||
/* xc STK_OFF_TCCNT(4,%r15),STK_OFF_TCCNT(%r15) */
|
||||
_EMIT6(0xd703f000 | STK_OFF_TCCNT, 0xf000 | STK_OFF_TCCNT);
|
||||
|
||||
+131
-18
@@ -16,6 +16,9 @@
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/text-patching.h>
|
||||
#include <asm/unwind.h>
|
||||
|
||||
static bool all_callee_regs_used[4] = {true, true, true, true};
|
||||
|
||||
static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
|
||||
{
|
||||
@@ -255,6 +258,14 @@ struct jit_context {
|
||||
/* Number of bytes that will be skipped on tailcall */
|
||||
#define X86_TAIL_CALL_OFFSET (11 + ENDBR_INSN_SIZE)
|
||||
|
||||
static void push_r12(u8 **pprog)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
|
||||
EMIT2(0x41, 0x54); /* push r12 */
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
static void push_callee_regs(u8 **pprog, bool *callee_regs_used)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
@@ -270,6 +281,14 @@ static void push_callee_regs(u8 **pprog, bool *callee_regs_used)
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
static void pop_r12(u8 **pprog)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
|
||||
EMIT2(0x41, 0x5C); /* pop r12 */
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
static void pop_callee_regs(u8 **pprog, bool *callee_regs_used)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
@@ -291,7 +310,8 @@ static void pop_callee_regs(u8 **pprog, bool *callee_regs_used)
|
||||
* while jumping to another program
|
||||
*/
|
||||
static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf,
|
||||
bool tail_call_reachable, bool is_subprog)
|
||||
bool tail_call_reachable, bool is_subprog,
|
||||
bool is_exception_cb)
|
||||
{
|
||||
u8 *prog = *pprog;
|
||||
|
||||
@@ -303,12 +323,30 @@ static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf,
|
||||
prog += X86_PATCH_SIZE;
|
||||
if (!ebpf_from_cbpf) {
|
||||
if (tail_call_reachable && !is_subprog)
|
||||
/* When it's the entry of the whole tailcall context,
|
||||
* zeroing rax means initialising tail_call_cnt.
|
||||
*/
|
||||
EMIT2(0x31, 0xC0); /* xor eax, eax */
|
||||
else
|
||||
/* Keep the same instruction layout. */
|
||||
EMIT2(0x66, 0x90); /* nop2 */
|
||||
}
|
||||
EMIT1(0x55); /* push rbp */
|
||||
EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */
|
||||
/* Exception callback receives FP as third parameter */
|
||||
if (is_exception_cb) {
|
||||
EMIT3(0x48, 0x89, 0xF4); /* mov rsp, rsi */
|
||||
EMIT3(0x48, 0x89, 0xD5); /* mov rbp, rdx */
|
||||
/* The main frame must have exception_boundary as true, so we
|
||||
* first restore those callee-saved regs from stack, before
|
||||
* reusing the stack frame.
|
||||
*/
|
||||
pop_callee_regs(&prog, all_callee_regs_used);
|
||||
pop_r12(&prog);
|
||||
/* Reset the stack frame. */
|
||||
EMIT3(0x48, 0x89, 0xEC); /* mov rsp, rbp */
|
||||
} else {
|
||||
EMIT1(0x55); /* push rbp */
|
||||
EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */
|
||||
}
|
||||
|
||||
/* X86_TAIL_CALL_OFFSET is here */
|
||||
EMIT_ENDBR();
|
||||
@@ -467,7 +505,8 @@ static void emit_return(u8 **pprog, u8 *ip)
|
||||
* goto *(prog->bpf_func + prologue_size);
|
||||
* out:
|
||||
*/
|
||||
static void emit_bpf_tail_call_indirect(u8 **pprog, bool *callee_regs_used,
|
||||
static void emit_bpf_tail_call_indirect(struct bpf_prog *bpf_prog,
|
||||
u8 **pprog, bool *callee_regs_used,
|
||||
u32 stack_depth, u8 *ip,
|
||||
struct jit_context *ctx)
|
||||
{
|
||||
@@ -517,7 +556,12 @@ static void emit_bpf_tail_call_indirect(u8 **pprog, bool *callee_regs_used,
|
||||
offset = ctx->tail_call_indirect_label - (prog + 2 - start);
|
||||
EMIT2(X86_JE, offset); /* je out */
|
||||
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
if (bpf_prog->aux->exception_boundary) {
|
||||
pop_callee_regs(&prog, all_callee_regs_used);
|
||||
pop_r12(&prog);
|
||||
} else {
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
}
|
||||
|
||||
EMIT1(0x58); /* pop rax */
|
||||
if (stack_depth)
|
||||
@@ -541,7 +585,8 @@ static void emit_bpf_tail_call_indirect(u8 **pprog, bool *callee_regs_used,
|
||||
*pprog = prog;
|
||||
}
|
||||
|
||||
static void emit_bpf_tail_call_direct(struct bpf_jit_poke_descriptor *poke,
|
||||
static void emit_bpf_tail_call_direct(struct bpf_prog *bpf_prog,
|
||||
struct bpf_jit_poke_descriptor *poke,
|
||||
u8 **pprog, u8 *ip,
|
||||
bool *callee_regs_used, u32 stack_depth,
|
||||
struct jit_context *ctx)
|
||||
@@ -570,7 +615,13 @@ static void emit_bpf_tail_call_direct(struct bpf_jit_poke_descriptor *poke,
|
||||
emit_jump(&prog, (u8 *)poke->tailcall_target + X86_PATCH_SIZE,
|
||||
poke->tailcall_bypass);
|
||||
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
if (bpf_prog->aux->exception_boundary) {
|
||||
pop_callee_regs(&prog, all_callee_regs_used);
|
||||
pop_r12(&prog);
|
||||
} else {
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
}
|
||||
|
||||
EMIT1(0x58); /* pop rax */
|
||||
if (stack_depth)
|
||||
EMIT3_off32(0x48, 0x81, 0xC4, round_up(stack_depth, 8));
|
||||
@@ -1018,6 +1069,10 @@ static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op)
|
||||
|
||||
#define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp)))
|
||||
|
||||
/* mov rax, qword ptr [rbp - rounded_stack_depth - 8] */
|
||||
#define RESTORE_TAIL_CALL_CNT(stack) \
|
||||
EMIT3_off32(0x48, 0x8B, 0x85, -round_up(stack, 8) - 8)
|
||||
|
||||
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
|
||||
int oldproglen, struct jit_context *ctx, bool jmp_padding)
|
||||
{
|
||||
@@ -1041,8 +1096,20 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
|
||||
|
||||
emit_prologue(&prog, bpf_prog->aux->stack_depth,
|
||||
bpf_prog_was_classic(bpf_prog), tail_call_reachable,
|
||||
bpf_prog->aux->func_idx != 0);
|
||||
push_callee_regs(&prog, callee_regs_used);
|
||||
bpf_is_subprog(bpf_prog), bpf_prog->aux->exception_cb);
|
||||
/* Exception callback will clobber callee regs for its own use, and
|
||||
* restore the original callee regs from main prog's stack frame.
|
||||
*/
|
||||
if (bpf_prog->aux->exception_boundary) {
|
||||
/* We also need to save r12, which is not mapped to any BPF
|
||||
* register, as we throw after entry into the kernel, which may
|
||||
* overwrite r12.
|
||||
*/
|
||||
push_r12(&prog);
|
||||
push_callee_regs(&prog, all_callee_regs_used);
|
||||
} else {
|
||||
push_callee_regs(&prog, callee_regs_used);
|
||||
}
|
||||
|
||||
ilen = prog - temp;
|
||||
if (rw_image)
|
||||
@@ -1623,9 +1690,7 @@ st: if (is_imm8(insn->off))
|
||||
|
||||
func = (u8 *) __bpf_call_base + imm32;
|
||||
if (tail_call_reachable) {
|
||||
/* mov rax, qword ptr [rbp - rounded_stack_depth - 8] */
|
||||
EMIT3_off32(0x48, 0x8B, 0x85,
|
||||
-round_up(bpf_prog->aux->stack_depth, 8) - 8);
|
||||
RESTORE_TAIL_CALL_CNT(bpf_prog->aux->stack_depth);
|
||||
if (!imm32)
|
||||
return -EINVAL;
|
||||
offs = 7 + x86_call_depth_emit_accounting(&prog, func);
|
||||
@@ -1641,13 +1706,15 @@ st: if (is_imm8(insn->off))
|
||||
|
||||
case BPF_JMP | BPF_TAIL_CALL:
|
||||
if (imm32)
|
||||
emit_bpf_tail_call_direct(&bpf_prog->aux->poke_tab[imm32 - 1],
|
||||
emit_bpf_tail_call_direct(bpf_prog,
|
||||
&bpf_prog->aux->poke_tab[imm32 - 1],
|
||||
&prog, image + addrs[i - 1],
|
||||
callee_regs_used,
|
||||
bpf_prog->aux->stack_depth,
|
||||
ctx);
|
||||
else
|
||||
emit_bpf_tail_call_indirect(&prog,
|
||||
emit_bpf_tail_call_indirect(bpf_prog,
|
||||
&prog,
|
||||
callee_regs_used,
|
||||
bpf_prog->aux->stack_depth,
|
||||
image + addrs[i - 1],
|
||||
@@ -1900,7 +1967,12 @@ emit_jmp:
|
||||
seen_exit = true;
|
||||
/* Update cleanup_addr */
|
||||
ctx->cleanup_addr = proglen;
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
if (bpf_prog->aux->exception_boundary) {
|
||||
pop_callee_regs(&prog, all_callee_regs_used);
|
||||
pop_r12(&prog);
|
||||
} else {
|
||||
pop_callee_regs(&prog, callee_regs_used);
|
||||
}
|
||||
EMIT1(0xC9); /* leave */
|
||||
emit_return(&prog, image + addrs[i - 1] + (prog - temp));
|
||||
break;
|
||||
@@ -2400,6 +2472,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
||||
* [ ... ]
|
||||
* [ stack_arg2 ]
|
||||
* RBP - arg_stack_off [ stack_arg1 ]
|
||||
* RSP [ tail_call_cnt ] BPF_TRAMP_F_TAIL_CALL_CTX
|
||||
*/
|
||||
|
||||
/* room for return value of orig_call or fentry prog */
|
||||
@@ -2464,6 +2537,8 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
||||
else
|
||||
/* sub rsp, stack_size */
|
||||
EMIT4(0x48, 0x83, 0xEC, stack_size);
|
||||
if (flags & BPF_TRAMP_F_TAIL_CALL_CTX)
|
||||
EMIT1(0x50); /* push rax */
|
||||
/* mov QWORD PTR [rbp - rbx_off], rbx */
|
||||
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_6, -rbx_off);
|
||||
|
||||
@@ -2516,9 +2591,15 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
||||
restore_regs(m, &prog, regs_off);
|
||||
save_args(m, &prog, arg_stack_off, true);
|
||||
|
||||
if (flags & BPF_TRAMP_F_TAIL_CALL_CTX)
|
||||
/* Before calling the original function, restore the
|
||||
* tail_call_cnt from stack to rax.
|
||||
*/
|
||||
RESTORE_TAIL_CALL_CNT(stack_size);
|
||||
|
||||
if (flags & BPF_TRAMP_F_ORIG_STACK) {
|
||||
emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, 8);
|
||||
EMIT2(0xff, 0xd0); /* call *rax */
|
||||
emit_ldx(&prog, BPF_DW, BPF_REG_6, BPF_REG_FP, 8);
|
||||
EMIT2(0xff, 0xd3); /* call *rbx */
|
||||
} else {
|
||||
/* call original function */
|
||||
if (emit_rsb_call(&prog, orig_call, prog)) {
|
||||
@@ -2569,7 +2650,12 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
|
||||
ret = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
} else if (flags & BPF_TRAMP_F_TAIL_CALL_CTX)
|
||||
/* Before running the original function, restore the
|
||||
* tail_call_cnt from stack to rax.
|
||||
*/
|
||||
RESTORE_TAIL_CALL_CNT(stack_size);
|
||||
|
||||
/* restore return value of orig_call or fentry prog back into RAX */
|
||||
if (save_ret)
|
||||
emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, -8);
|
||||
@@ -2913,3 +2999,30 @@ void bpf_jit_free(struct bpf_prog *prog)
|
||||
|
||||
bpf_prog_unlock_free(prog);
|
||||
}
|
||||
|
||||
bool bpf_jit_supports_exceptions(void)
|
||||
{
|
||||
/* We unwind through both kernel frames (starting from within bpf_throw
|
||||
* call) and BPF frames. Therefore we require one of ORC or FP unwinder
|
||||
* to be enabled to walk kernel frames and reach BPF frames in the stack
|
||||
* trace.
|
||||
*/
|
||||
return IS_ENABLED(CONFIG_UNWINDER_ORC) || IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER);
|
||||
}
|
||||
|
||||
void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
|
||||
{
|
||||
#if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER)
|
||||
struct unwind_state state;
|
||||
unsigned long addr;
|
||||
|
||||
for (unwind_start(&state, current, NULL, NULL); !unwind_done(&state);
|
||||
unwind_next_frame(&state)) {
|
||||
addr = unwind_get_return_address(&state);
|
||||
if (!addr || !consume_fn(cookie, (u64)addr, (u64)state.sp, (u64)state.bp))
|
||||
break;
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
WARN(1, "verification of programs using bpf_throw should have failed\n");
|
||||
}
|
||||
|
||||
+31
-9
@@ -55,8 +55,8 @@ struct cgroup;
|
||||
extern struct idr btf_idr;
|
||||
extern spinlock_t btf_idr_lock;
|
||||
extern struct kobject *btf_kobj;
|
||||
extern struct bpf_mem_alloc bpf_global_ma;
|
||||
extern bool bpf_global_ma_set;
|
||||
extern struct bpf_mem_alloc bpf_global_ma, bpf_global_percpu_ma;
|
||||
extern bool bpf_global_ma_set, bpf_global_percpu_ma_set;
|
||||
|
||||
typedef u64 (*bpf_callback_t)(u64, u64, u64, u64, u64);
|
||||
typedef int (*bpf_iter_init_seq_priv_t)(void *private_data,
|
||||
@@ -180,14 +180,15 @@ enum btf_field_type {
|
||||
BPF_TIMER = (1 << 1),
|
||||
BPF_KPTR_UNREF = (1 << 2),
|
||||
BPF_KPTR_REF = (1 << 3),
|
||||
BPF_KPTR = BPF_KPTR_UNREF | BPF_KPTR_REF,
|
||||
BPF_LIST_HEAD = (1 << 4),
|
||||
BPF_LIST_NODE = (1 << 5),
|
||||
BPF_RB_ROOT = (1 << 6),
|
||||
BPF_RB_NODE = (1 << 7),
|
||||
BPF_KPTR_PERCPU = (1 << 4),
|
||||
BPF_KPTR = BPF_KPTR_UNREF | BPF_KPTR_REF | BPF_KPTR_PERCPU,
|
||||
BPF_LIST_HEAD = (1 << 5),
|
||||
BPF_LIST_NODE = (1 << 6),
|
||||
BPF_RB_ROOT = (1 << 7),
|
||||
BPF_RB_NODE = (1 << 8),
|
||||
BPF_GRAPH_NODE_OR_ROOT = BPF_LIST_NODE | BPF_LIST_HEAD |
|
||||
BPF_RB_NODE | BPF_RB_ROOT,
|
||||
BPF_REFCOUNT = (1 << 8),
|
||||
BPF_REFCOUNT = (1 << 9),
|
||||
};
|
||||
|
||||
typedef void (*btf_dtor_kfunc_t)(void *);
|
||||
@@ -300,6 +301,8 @@ static inline const char *btf_field_type_name(enum btf_field_type type)
|
||||
case BPF_KPTR_UNREF:
|
||||
case BPF_KPTR_REF:
|
||||
return "kptr";
|
||||
case BPF_KPTR_PERCPU:
|
||||
return "percpu_kptr";
|
||||
case BPF_LIST_HEAD:
|
||||
return "bpf_list_head";
|
||||
case BPF_LIST_NODE:
|
||||
@@ -325,6 +328,7 @@ static inline u32 btf_field_type_size(enum btf_field_type type)
|
||||
return sizeof(struct bpf_timer);
|
||||
case BPF_KPTR_UNREF:
|
||||
case BPF_KPTR_REF:
|
||||
case BPF_KPTR_PERCPU:
|
||||
return sizeof(u64);
|
||||
case BPF_LIST_HEAD:
|
||||
return sizeof(struct bpf_list_head);
|
||||
@@ -351,6 +355,7 @@ static inline u32 btf_field_type_align(enum btf_field_type type)
|
||||
return __alignof__(struct bpf_timer);
|
||||
case BPF_KPTR_UNREF:
|
||||
case BPF_KPTR_REF:
|
||||
case BPF_KPTR_PERCPU:
|
||||
return __alignof__(u64);
|
||||
case BPF_LIST_HEAD:
|
||||
return __alignof__(struct bpf_list_head);
|
||||
@@ -389,6 +394,7 @@ static inline void bpf_obj_init_field(const struct btf_field *field, void *addr)
|
||||
case BPF_TIMER:
|
||||
case BPF_KPTR_UNREF:
|
||||
case BPF_KPTR_REF:
|
||||
case BPF_KPTR_PERCPU:
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
@@ -1029,6 +1035,11 @@ struct btf_func_model {
|
||||
*/
|
||||
#define BPF_TRAMP_F_SHARE_IPMODIFY BIT(6)
|
||||
|
||||
/* Indicate that current trampoline is in a tail call context. Then, it has to
|
||||
* cache and restore tail_call_cnt to avoid infinite tail call loop.
|
||||
*/
|
||||
#define BPF_TRAMP_F_TAIL_CALL_CTX BIT(7)
|
||||
|
||||
/* Each call __bpf_prog_enter + call bpf_func + call __bpf_prog_exit is ~50
|
||||
* bytes on x86.
|
||||
*/
|
||||
@@ -1378,6 +1389,7 @@ struct bpf_prog_aux {
|
||||
u32 stack_depth;
|
||||
u32 id;
|
||||
u32 func_cnt; /* used by non-func prog as the number of func progs */
|
||||
u32 real_func_cnt; /* includes hidden progs, only used for JIT and freeing progs */
|
||||
u32 func_idx; /* 0 for non-func prog, the index in func array for func prog */
|
||||
u32 attach_btf_id; /* in-kernel BTF type id to attach to */
|
||||
u32 ctx_arg_info_size;
|
||||
@@ -1398,6 +1410,8 @@ struct bpf_prog_aux {
|
||||
bool sleepable;
|
||||
bool tail_call_reachable;
|
||||
bool xdp_has_frags;
|
||||
bool exception_cb;
|
||||
bool exception_boundary;
|
||||
/* BTF_KIND_FUNC_PROTO for valid attach_btf_id */
|
||||
const struct btf_type *attach_func_proto;
|
||||
/* function name for valid attach_btf_id */
|
||||
@@ -1420,6 +1434,7 @@ struct bpf_prog_aux {
|
||||
int cgroup_atype; /* enum cgroup_bpf_attach_type */
|
||||
struct bpf_map *cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE];
|
||||
char name[BPF_OBJ_NAME_LEN];
|
||||
unsigned int (*bpf_exception_cb)(u64 cookie, u64 sp, u64 bp);
|
||||
#ifdef CONFIG_SECURITY
|
||||
void *security;
|
||||
#endif
|
||||
@@ -2407,9 +2422,11 @@ int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog,
|
||||
int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
|
||||
struct bpf_reg_state *regs);
|
||||
int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
|
||||
struct bpf_reg_state *reg);
|
||||
struct bpf_reg_state *reg, bool is_ex_cb);
|
||||
int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *prog,
|
||||
struct btf *btf, const struct btf_type *t);
|
||||
const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type *pt,
|
||||
int comp_idx, const char *tag_key);
|
||||
|
||||
struct bpf_prog *bpf_prog_by_id(u32 id);
|
||||
struct bpf_link *bpf_link_by_id(u32 id);
|
||||
@@ -3183,4 +3200,9 @@ static inline gfp_t bpf_memcg_flags(gfp_t flags)
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline bool bpf_is_subprog(const struct bpf_prog *prog)
|
||||
{
|
||||
return prog->aux->func_idx != 0;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_BPF_H */
|
||||
|
||||
@@ -300,6 +300,7 @@ struct bpf_func_state {
|
||||
bool in_callback_fn;
|
||||
struct tnum callback_ret_range;
|
||||
bool in_async_callback_fn;
|
||||
bool in_exception_callback_fn;
|
||||
|
||||
/* The following fields should be last. See copy_func_state() */
|
||||
int acquired_refs;
|
||||
@@ -480,6 +481,7 @@ struct bpf_insn_aux_data {
|
||||
bool zext_dst; /* this insn zero extends dst reg */
|
||||
bool storage_get_func_atomic; /* bpf_*_storage_get() with atomic memory alloc */
|
||||
bool is_iter_next; /* bpf_iter_<type>_next() kfunc call */
|
||||
bool call_with_percpu_alloc_ptr; /* {this,per}_cpu_ptr() with prog percpu alloc */
|
||||
u8 alu_state; /* used in combination with alu_limit */
|
||||
|
||||
/* below fields are initialized once */
|
||||
@@ -540,7 +542,9 @@ struct bpf_subprog_info {
|
||||
bool has_tail_call;
|
||||
bool tail_call_reachable;
|
||||
bool has_ld_abs;
|
||||
bool is_cb;
|
||||
bool is_async_cb;
|
||||
bool is_exception_cb;
|
||||
};
|
||||
|
||||
struct bpf_verifier_env;
|
||||
@@ -587,6 +591,8 @@ struct bpf_verifier_env {
|
||||
u32 used_map_cnt; /* number of used maps */
|
||||
u32 used_btf_cnt; /* number of used BTF objects */
|
||||
u32 id_gen; /* used to generate unique reg IDs */
|
||||
u32 hidden_subprog_cnt; /* number of hidden subprogs */
|
||||
int exception_callback_subprog;
|
||||
bool explore_alu_limits;
|
||||
bool allow_ptr_leaks;
|
||||
bool allow_uninit_stack;
|
||||
@@ -594,10 +600,11 @@ struct bpf_verifier_env {
|
||||
bool bypass_spec_v1;
|
||||
bool bypass_spec_v4;
|
||||
bool seen_direct_write;
|
||||
bool seen_exception;
|
||||
struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
|
||||
const struct bpf_line_info *prev_linfo;
|
||||
struct bpf_verifier_log log;
|
||||
struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1];
|
||||
struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 2]; /* max + 2 for the fake and exception subprogs */
|
||||
union {
|
||||
struct bpf_idmap idmap_scratch;
|
||||
struct bpf_idset idset_scratch;
|
||||
|
||||
+54
-4
@@ -117,21 +117,25 @@ struct ctl_table_header;
|
||||
|
||||
/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */
|
||||
|
||||
#define BPF_ALU64_IMM(OP, DST, IMM) \
|
||||
#define BPF_ALU64_IMM_OFF(OP, DST, IMM, OFF) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
|
||||
.dst_reg = DST, \
|
||||
.src_reg = 0, \
|
||||
.off = 0, \
|
||||
.off = OFF, \
|
||||
.imm = IMM })
|
||||
#define BPF_ALU64_IMM(OP, DST, IMM) \
|
||||
BPF_ALU64_IMM_OFF(OP, DST, IMM, 0)
|
||||
|
||||
#define BPF_ALU32_IMM(OP, DST, IMM) \
|
||||
#define BPF_ALU32_IMM_OFF(OP, DST, IMM, OFF) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_ALU | BPF_OP(OP) | BPF_K, \
|
||||
.dst_reg = DST, \
|
||||
.src_reg = 0, \
|
||||
.off = 0, \
|
||||
.off = OFF, \
|
||||
.imm = IMM })
|
||||
#define BPF_ALU32_IMM(OP, DST, IMM) \
|
||||
BPF_ALU32_IMM_OFF(OP, DST, IMM, 0)
|
||||
|
||||
/* Endianess conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */
|
||||
|
||||
@@ -143,6 +147,16 @@ struct ctl_table_header;
|
||||
.off = 0, \
|
||||
.imm = LEN })
|
||||
|
||||
/* Byte Swap, bswap16/32/64 */
|
||||
|
||||
#define BPF_BSWAP(DST, LEN) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_ALU64 | BPF_END | BPF_SRC(BPF_TO_LE), \
|
||||
.dst_reg = DST, \
|
||||
.src_reg = 0, \
|
||||
.off = 0, \
|
||||
.imm = LEN })
|
||||
|
||||
/* Short form of mov, dst_reg = src_reg */
|
||||
|
||||
#define BPF_MOV64_REG(DST, SRC) \
|
||||
@@ -179,6 +193,24 @@ struct ctl_table_header;
|
||||
.off = 0, \
|
||||
.imm = IMM })
|
||||
|
||||
/* Short form of movsx, dst_reg = (s8,s16,s32)src_reg */
|
||||
|
||||
#define BPF_MOVSX64_REG(DST, SRC, OFF) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_ALU64 | BPF_MOV | BPF_X, \
|
||||
.dst_reg = DST, \
|
||||
.src_reg = SRC, \
|
||||
.off = OFF, \
|
||||
.imm = 0 })
|
||||
|
||||
#define BPF_MOVSX32_REG(DST, SRC, OFF) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_ALU | BPF_MOV | BPF_X, \
|
||||
.dst_reg = DST, \
|
||||
.src_reg = SRC, \
|
||||
.off = OFF, \
|
||||
.imm = 0 })
|
||||
|
||||
/* Special form of mov32, used for doing explicit zero extension on dst. */
|
||||
#define BPF_ZEXT_REG(DST) \
|
||||
((struct bpf_insn) { \
|
||||
@@ -263,6 +295,16 @@ static inline bool insn_is_zext(const struct bpf_insn *insn)
|
||||
.off = OFF, \
|
||||
.imm = 0 })
|
||||
|
||||
/* Memory load, dst_reg = *(signed size *) (src_reg + off16) */
|
||||
|
||||
#define BPF_LDX_MEMSX(SIZE, DST, SRC, OFF) \
|
||||
((struct bpf_insn) { \
|
||||
.code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEMSX, \
|
||||
.dst_reg = DST, \
|
||||
.src_reg = SRC, \
|
||||
.off = OFF, \
|
||||
.imm = 0 })
|
||||
|
||||
/* Memory store, *(uint *) (dst_reg + off16) = src_reg */
|
||||
|
||||
#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \
|
||||
@@ -912,6 +954,8 @@ bool bpf_jit_needs_zext(void);
|
||||
bool bpf_jit_supports_subprog_tailcalls(void);
|
||||
bool bpf_jit_supports_kfunc_call(void);
|
||||
bool bpf_jit_supports_far_kfunc_call(void);
|
||||
bool bpf_jit_supports_exceptions(void);
|
||||
void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie);
|
||||
bool bpf_helper_changes_pkt_data(void *func);
|
||||
|
||||
static inline bool bpf_dump_raw_ok(const struct cred *cred)
|
||||
@@ -1127,6 +1171,7 @@ const char *__bpf_address_lookup(unsigned long addr, unsigned long *size,
|
||||
bool is_bpf_text_address(unsigned long addr);
|
||||
int bpf_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
|
||||
char *sym);
|
||||
struct bpf_prog *bpf_prog_ksym_find(unsigned long addr);
|
||||
|
||||
static inline const char *
|
||||
bpf_address_lookup(unsigned long addr, unsigned long *size,
|
||||
@@ -1194,6 +1239,11 @@ static inline int bpf_get_kallsym(unsigned int symnum, unsigned long *value,
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
static inline struct bpf_prog *bpf_prog_ksym_find(unsigned long addr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
bpf_address_lookup(unsigned long addr, unsigned long *size,
|
||||
unsigned long *off, char **modname, char *sym)
|
||||
|
||||
@@ -285,8 +285,10 @@ static inline bool kasan_check_byte(const void *address)
|
||||
|
||||
#if defined(CONFIG_KASAN) && defined(CONFIG_KASAN_STACK)
|
||||
void kasan_unpoison_task_stack(struct task_struct *task);
|
||||
asmlinkage void kasan_unpoison_task_stack_below(const void *watermark);
|
||||
#else
|
||||
static inline void kasan_unpoison_task_stack(struct task_struct *task) {}
|
||||
static inline void kasan_unpoison_task_stack_below(const void *watermark) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KASAN_GENERIC
|
||||
|
||||
+15
-4
@@ -383,14 +383,25 @@ void xdp_attachment_setup(struct xdp_attachment_info *info,
|
||||
|
||||
#define DEV_MAP_BULK_SIZE XDP_BULK_QUEUE_SIZE
|
||||
|
||||
/* Define the relationship between xdp-rx-metadata kfunc and
|
||||
* various other entities:
|
||||
* - xdp_rx_metadata enum
|
||||
* - netdev netlink enum (Documentation/netlink/specs/netdev.yaml)
|
||||
* - kfunc name
|
||||
* - xdp_metadata_ops field
|
||||
*/
|
||||
#define XDP_METADATA_KFUNC_xxx \
|
||||
XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_TIMESTAMP, \
|
||||
bpf_xdp_metadata_rx_timestamp) \
|
||||
NETDEV_XDP_RX_METADATA_TIMESTAMP, \
|
||||
bpf_xdp_metadata_rx_timestamp, \
|
||||
xmo_rx_timestamp) \
|
||||
XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_HASH, \
|
||||
bpf_xdp_metadata_rx_hash) \
|
||||
NETDEV_XDP_RX_METADATA_HASH, \
|
||||
bpf_xdp_metadata_rx_hash, \
|
||||
xmo_rx_hash) \
|
||||
|
||||
enum {
|
||||
#define XDP_METADATA_KFUNC(name, _) name,
|
||||
enum xdp_rx_metadata {
|
||||
#define XDP_METADATA_KFUNC(name, _, __, ___) name,
|
||||
XDP_METADATA_KFUNC_xxx
|
||||
#undef XDP_METADATA_KFUNC
|
||||
MAX_XDP_METADATA_KFUNC,
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <linux/mm.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#define XDP_UMEM_SG_FLAG (1 << 1)
|
||||
|
||||
struct net_device;
|
||||
struct xsk_queue;
|
||||
struct xdp_buff;
|
||||
|
||||
@@ -932,7 +932,14 @@ enum bpf_map_type {
|
||||
*/
|
||||
BPF_MAP_TYPE_CGROUP_STORAGE = BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED,
|
||||
BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
|
||||
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
|
||||
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED,
|
||||
/* BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE is available to bpf programs
|
||||
* attaching to a cgroup. The new mechanism (BPF_MAP_TYPE_CGRP_STORAGE +
|
||||
* local percpu kptr) supports all BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE
|
||||
* functionality and more. So mark * BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE
|
||||
* deprecated.
|
||||
*/
|
||||
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE_DEPRECATED,
|
||||
BPF_MAP_TYPE_QUEUE,
|
||||
BPF_MAP_TYPE_STACK,
|
||||
BPF_MAP_TYPE_SK_STORAGE,
|
||||
|
||||
@@ -38,11 +38,27 @@ enum netdev_xdp_act {
|
||||
NETDEV_XDP_ACT_MASK = 127,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum netdev_xdp_rx_metadata
|
||||
* @NETDEV_XDP_RX_METADATA_TIMESTAMP: Device is capable of exposing receive HW
|
||||
* timestamp via bpf_xdp_metadata_rx_timestamp().
|
||||
* @NETDEV_XDP_RX_METADATA_HASH: Device is capable of exposing receive packet
|
||||
* hash via bpf_xdp_metadata_rx_hash().
|
||||
*/
|
||||
enum netdev_xdp_rx_metadata {
|
||||
NETDEV_XDP_RX_METADATA_TIMESTAMP = 1,
|
||||
NETDEV_XDP_RX_METADATA_HASH = 2,
|
||||
|
||||
/* private: */
|
||||
NETDEV_XDP_RX_METADATA_MASK = 3,
|
||||
};
|
||||
|
||||
enum {
|
||||
NETDEV_A_DEV_IFINDEX = 1,
|
||||
NETDEV_A_DEV_PAD,
|
||||
NETDEV_A_DEV_XDP_FEATURES,
|
||||
NETDEV_A_DEV_XDP_ZC_MAX_SEGS,
|
||||
NETDEV_A_DEV_XDP_RX_METADATA_FEATURES,
|
||||
|
||||
__NETDEV_A_DEV_MAX,
|
||||
NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1)
|
||||
|
||||
@@ -615,7 +615,10 @@ static void __bpf_struct_ops_map_free(struct bpf_map *map)
|
||||
if (st_map->links)
|
||||
bpf_struct_ops_map_put_progs(st_map);
|
||||
bpf_map_area_free(st_map->links);
|
||||
bpf_jit_free_exec(st_map->image);
|
||||
if (st_map->image) {
|
||||
bpf_jit_free_exec(st_map->image);
|
||||
bpf_jit_uncharge_modmem(PAGE_SIZE);
|
||||
}
|
||||
bpf_map_area_free(st_map->uvalue);
|
||||
bpf_map_area_free(st_map);
|
||||
}
|
||||
@@ -657,6 +660,7 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
|
||||
struct bpf_struct_ops_map *st_map;
|
||||
const struct btf_type *t, *vt;
|
||||
struct bpf_map *map;
|
||||
int ret;
|
||||
|
||||
st_ops = bpf_struct_ops_find_value(attr->btf_vmlinux_value_type_id);
|
||||
if (!st_ops)
|
||||
@@ -681,12 +685,27 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
|
||||
st_map->st_ops = st_ops;
|
||||
map = &st_map->map;
|
||||
|
||||
ret = bpf_jit_charge_modmem(PAGE_SIZE);
|
||||
if (ret) {
|
||||
__bpf_struct_ops_map_free(map);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
st_map->image = bpf_jit_alloc_exec(PAGE_SIZE);
|
||||
if (!st_map->image) {
|
||||
/* __bpf_struct_ops_map_free() uses st_map->image as flag
|
||||
* for "charged or not". In this case, we need to unchange
|
||||
* here.
|
||||
*/
|
||||
bpf_jit_uncharge_modmem(PAGE_SIZE);
|
||||
__bpf_struct_ops_map_free(map);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
st_map->uvalue = bpf_map_area_alloc(vt->size, NUMA_NO_NODE);
|
||||
st_map->links =
|
||||
bpf_map_area_alloc(btf_type_vlen(t) * sizeof(struct bpf_links *),
|
||||
NUMA_NO_NODE);
|
||||
st_map->image = bpf_jit_alloc_exec(PAGE_SIZE);
|
||||
if (!st_map->uvalue || !st_map->links || !st_map->image) {
|
||||
if (!st_map->uvalue || !st_map->links) {
|
||||
__bpf_struct_ops_map_free(map);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
@@ -907,4 +926,3 @@ err_out:
|
||||
kfree(link);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
+26
-8
@@ -3293,6 +3293,8 @@ static int btf_find_kptr(const struct btf *btf, const struct btf_type *t,
|
||||
type = BPF_KPTR_UNREF;
|
||||
else if (!strcmp("kptr", __btf_name_by_offset(btf, t->name_off)))
|
||||
type = BPF_KPTR_REF;
|
||||
else if (!strcmp("percpu_kptr", __btf_name_by_offset(btf, t->name_off)))
|
||||
type = BPF_KPTR_PERCPU;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
@@ -3308,10 +3310,10 @@ static int btf_find_kptr(const struct btf *btf, const struct btf_type *t,
|
||||
return BTF_FIELD_FOUND;
|
||||
}
|
||||
|
||||
static const char *btf_find_decl_tag_value(const struct btf *btf,
|
||||
const struct btf_type *pt,
|
||||
int comp_idx, const char *tag_key)
|
||||
const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type *pt,
|
||||
int comp_idx, const char *tag_key)
|
||||
{
|
||||
const char *value = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < btf_nr_types(btf); i++) {
|
||||
@@ -3325,9 +3327,14 @@ static const char *btf_find_decl_tag_value(const struct btf *btf,
|
||||
continue;
|
||||
if (strncmp(__btf_name_by_offset(btf, t->name_off), tag_key, len))
|
||||
continue;
|
||||
return __btf_name_by_offset(btf, t->name_off) + len;
|
||||
/* Prevent duplicate entries for same type */
|
||||
if (value)
|
||||
return ERR_PTR(-EEXIST);
|
||||
value = __btf_name_by_offset(btf, t->name_off) + len;
|
||||
}
|
||||
return NULL;
|
||||
if (!value)
|
||||
return ERR_PTR(-ENOENT);
|
||||
return value;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3345,7 +3352,7 @@ btf_find_graph_root(const struct btf *btf, const struct btf_type *pt,
|
||||
if (t->size != sz)
|
||||
return BTF_FIELD_IGNORE;
|
||||
value_type = btf_find_decl_tag_value(btf, pt, comp_idx, "contains:");
|
||||
if (!value_type)
|
||||
if (IS_ERR(value_type))
|
||||
return -EINVAL;
|
||||
node_field_name = strstr(value_type, ":");
|
||||
if (!node_field_name)
|
||||
@@ -3457,6 +3464,7 @@ static int btf_find_struct_field(const struct btf *btf,
|
||||
break;
|
||||
case BPF_KPTR_UNREF:
|
||||
case BPF_KPTR_REF:
|
||||
case BPF_KPTR_PERCPU:
|
||||
ret = btf_find_kptr(btf, member_type, off, sz,
|
||||
idx < info_cnt ? &info[idx] : &tmp);
|
||||
if (ret < 0)
|
||||
@@ -3523,6 +3531,7 @@ static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t,
|
||||
break;
|
||||
case BPF_KPTR_UNREF:
|
||||
case BPF_KPTR_REF:
|
||||
case BPF_KPTR_PERCPU:
|
||||
ret = btf_find_kptr(btf, var_type, off, sz,
|
||||
idx < info_cnt ? &info[idx] : &tmp);
|
||||
if (ret < 0)
|
||||
@@ -3783,6 +3792,7 @@ struct btf_record *btf_parse_fields(const struct btf *btf, const struct btf_type
|
||||
break;
|
||||
case BPF_KPTR_UNREF:
|
||||
case BPF_KPTR_REF:
|
||||
case BPF_KPTR_PERCPU:
|
||||
ret = btf_parse_kptr(btf, &rec->fields[i], &info_arr[i]);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
@@ -6949,7 +6959,7 @@ int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
|
||||
* (either PTR_TO_CTX or SCALAR_VALUE).
|
||||
*/
|
||||
int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
|
||||
struct bpf_reg_state *regs)
|
||||
struct bpf_reg_state *regs, bool is_ex_cb)
|
||||
{
|
||||
struct bpf_verifier_log *log = &env->log;
|
||||
struct bpf_prog *prog = env->prog;
|
||||
@@ -7006,7 +7016,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
|
||||
tname, nargs, MAX_BPF_FUNC_REG_ARGS);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* check that function returns int */
|
||||
/* check that function returns int, exception cb also requires this */
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
while (btf_type_is_modifier(t))
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
@@ -7055,6 +7065,14 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
|
||||
i, btf_type_str(t), tname);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* We have already ensured that the callback returns an integer, just
|
||||
* like all global subprogs. We need to determine it only has a single
|
||||
* scalar argument.
|
||||
*/
|
||||
if (is_ex_cb && (nargs != 1 || regs[BPF_REG_1].type != SCALAR_VALUE)) {
|
||||
bpf_log(log, "exception cb only supports single integer argument\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+26
-11
@@ -64,8 +64,8 @@
|
||||
#define OFF insn->off
|
||||
#define IMM insn->imm
|
||||
|
||||
struct bpf_mem_alloc bpf_global_ma;
|
||||
bool bpf_global_ma_set;
|
||||
struct bpf_mem_alloc bpf_global_ma, bpf_global_percpu_ma;
|
||||
bool bpf_global_ma_set, bpf_global_percpu_ma_set;
|
||||
|
||||
/* No hurry in this branch
|
||||
*
|
||||
@@ -212,7 +212,7 @@ void bpf_prog_fill_jited_linfo(struct bpf_prog *prog,
|
||||
const struct bpf_line_info *linfo;
|
||||
void **jited_linfo;
|
||||
|
||||
if (!prog->aux->jited_linfo)
|
||||
if (!prog->aux->jited_linfo || prog->aux->func_idx > prog->aux->func_cnt)
|
||||
/* Userspace did not provide linfo */
|
||||
return;
|
||||
|
||||
@@ -539,7 +539,7 @@ static void bpf_prog_kallsyms_del_subprogs(struct bpf_prog *fp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fp->aux->func_cnt; i++)
|
||||
for (i = 0; i < fp->aux->real_func_cnt; i++)
|
||||
bpf_prog_kallsyms_del(fp->aux->func[i]);
|
||||
}
|
||||
|
||||
@@ -589,7 +589,7 @@ bpf_prog_ksym_set_name(struct bpf_prog *prog)
|
||||
sym = bin2hex(sym, prog->tag, sizeof(prog->tag));
|
||||
|
||||
/* prog->aux->name will be ignored if full btf name is available */
|
||||
if (prog->aux->func_info_cnt) {
|
||||
if (prog->aux->func_info_cnt && prog->aux->func_idx < prog->aux->func_info_cnt) {
|
||||
type = btf_type_by_id(prog->aux->btf,
|
||||
prog->aux->func_info[prog->aux->func_idx].type_id);
|
||||
func_name = btf_name_by_offset(prog->aux->btf, type->name_off);
|
||||
@@ -623,7 +623,11 @@ static __always_inline int bpf_tree_comp(void *key, struct latch_tree_node *n)
|
||||
|
||||
if (val < ksym->start)
|
||||
return -1;
|
||||
if (val >= ksym->end)
|
||||
/* Ensure that we detect return addresses as part of the program, when
|
||||
* the final instruction is a call for a program part of the stack
|
||||
* trace. Therefore, do val > ksym->end instead of val >= ksym->end.
|
||||
*/
|
||||
if (val > ksym->end)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -733,7 +737,7 @@ bool is_bpf_text_address(unsigned long addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct bpf_prog *bpf_prog_ksym_find(unsigned long addr)
|
||||
struct bpf_prog *bpf_prog_ksym_find(unsigned long addr)
|
||||
{
|
||||
struct bpf_ksym *ksym = bpf_ksym_find(addr);
|
||||
|
||||
@@ -1208,7 +1212,7 @@ int bpf_jit_get_func_addr(const struct bpf_prog *prog,
|
||||
if (!extra_pass)
|
||||
addr = NULL;
|
||||
else if (prog->aux->func &&
|
||||
off >= 0 && off < prog->aux->func_cnt)
|
||||
off >= 0 && off < prog->aux->real_func_cnt)
|
||||
addr = (u8 *)prog->aux->func[off]->bpf_func;
|
||||
else
|
||||
return -EINVAL;
|
||||
@@ -2721,7 +2725,7 @@ static void bpf_prog_free_deferred(struct work_struct *work)
|
||||
#endif
|
||||
if (aux->dst_trampoline)
|
||||
bpf_trampoline_put(aux->dst_trampoline);
|
||||
for (i = 0; i < aux->func_cnt; i++) {
|
||||
for (i = 0; i < aux->real_func_cnt; i++) {
|
||||
/* We can just unlink the subprog poke descriptor table as
|
||||
* it was originally linked to the main program and is also
|
||||
* released along with it.
|
||||
@@ -2729,7 +2733,7 @@ static void bpf_prog_free_deferred(struct work_struct *work)
|
||||
aux->func[i]->aux->poke_tab = NULL;
|
||||
bpf_jit_free(aux->func[i]);
|
||||
}
|
||||
if (aux->func_cnt) {
|
||||
if (aux->real_func_cnt) {
|
||||
kfree(aux->func);
|
||||
bpf_prog_unlock_free(aux->prog);
|
||||
} else {
|
||||
@@ -2914,6 +2918,15 @@ int __weak bpf_arch_text_invalidate(void *dst, size_t len)
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
bool __weak bpf_jit_supports_exceptions(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void __weak arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BPF_SYSCALL
|
||||
static int __init bpf_global_ma_init(void)
|
||||
{
|
||||
@@ -2921,7 +2934,9 @@ static int __init bpf_global_ma_init(void)
|
||||
|
||||
ret = bpf_mem_alloc_init(&bpf_global_ma, 0, false);
|
||||
bpf_global_ma_set = !ret;
|
||||
return ret;
|
||||
ret = bpf_mem_alloc_init(&bpf_global_percpu_ma, 0, true);
|
||||
bpf_global_percpu_ma_set = !ret;
|
||||
return !bpf_global_ma_set || !bpf_global_percpu_ma_set;
|
||||
}
|
||||
late_initcall(bpf_global_ma_init);
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user