mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-17 20:54:10 +00:00
bpf-next pull-request 2023-08-09
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQRdM/uy1Ege0+EN1fNar9k/UBDW4wUCZNRx8QAKCRBar9k/UBDW 46MBAQC3YDFsEfPzX4P7ZnlM5Lf1NynjNbso5bYW0TF/dp/Y+gD+M8wdM5Vj2Mb0 Zr56TnwCJei0kGBemiel4sStt3e4qwY= =+0u+ -----END PGP SIGNATURE----- Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next Martin KaFai Lau says: ==================== pull-request: bpf-next 2023-08-09 We've added 19 non-merge commits during the last 6 day(s) which contain a total of 25 files changed, 369 insertions(+), 141 deletions(-). The main changes are: 1) Fix array-index-out-of-bounds access when detaching from an already empty mprog entry from Daniel Borkmann. 2) Adjust bpf selftest because of a recent llvm change related to the cpu-v4 ISA from Eduard Zingerman. 3) Add uprobe support for the bpf_get_func_ip helper from Jiri Olsa. 4) Fix a KASAN splat due to the kernel incorrectly accepted an invalid program using the recent cpu-v4 instruction from Yonghong Song. * tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next: bpf: btf: Remove two unused function declarations bpf: lru: Remove unused declaration bpf_lru_promote() selftests/bpf: relax expected log messages to allow emitting BPF_ST selftests/bpf: remove duplicated functions bpf, docs: Fix small typo and define semantics of sign extension selftests/bpf: Add bpf_get_func_ip test for uprobe inside function selftests/bpf: Add bpf_get_func_ip tests for uprobe on function entry bpf: Add support for bpf_get_func_ip helper for uprobe program selftests/bpf: Add a movsx selftest for sign-extension of R10 bpf: Fix an incorrect verification success with movsx insn bpf, docs: Formalize type notation and function semantics in ISA standard bpf: change bpf_alu_sign_string and bpf_movsx_string to static libbpf: Use local includes inside the library bpf: fix bpf_dynptr_slice() to stop return an ERR_PTR. bpf: fix inconsistent return types of bpf_xdp_copy_buf(). selftests/bpf: fix the incorrect verification of port numbers. selftests/bpf: Add test for detachment on empty mprog entry bpf: Fix mprog detachment for empty mprog entry bpf: bpf_struct_ops: Remove unnecessary initial values of variables ==================== Link: https://lore.kernel.org/r/20230810055123.109578-1-martin.lau@linux.dev Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
6a1ed1430d
25 changed files with 368 additions and 140 deletions
|
@ -10,9 +10,92 @@ This document specifies version 1.0 of the eBPF instruction set.
|
||||||
Documentation conventions
|
Documentation conventions
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
For brevity, this document uses the type notion "u64", "u32", etc.
|
For brevity and consistency, this document refers to families
|
||||||
to mean an unsigned integer whose width is the specified number of bits,
|
of types using a shorthand syntax and refers to several expository,
|
||||||
and "s32", etc. to mean a signed integer of the specified number of bits.
|
mnemonic functions when describing the semantics of instructions.
|
||||||
|
The range of valid values for those types and the semantics of those
|
||||||
|
functions are defined in the following subsections.
|
||||||
|
|
||||||
|
Types
|
||||||
|
-----
|
||||||
|
This document refers to integer types with the notation `SN` to specify
|
||||||
|
a type's signedness (`S`) and bit width (`N`), respectively.
|
||||||
|
|
||||||
|
.. table:: Meaning of signedness notation.
|
||||||
|
|
||||||
|
==== =========
|
||||||
|
`S` Meaning
|
||||||
|
==== =========
|
||||||
|
`u` unsigned
|
||||||
|
`s` signed
|
||||||
|
==== =========
|
||||||
|
|
||||||
|
.. table:: Meaning of bit-width notation.
|
||||||
|
|
||||||
|
===== =========
|
||||||
|
`N` Bit width
|
||||||
|
===== =========
|
||||||
|
`8` 8 bits
|
||||||
|
`16` 16 bits
|
||||||
|
`32` 32 bits
|
||||||
|
`64` 64 bits
|
||||||
|
`128` 128 bits
|
||||||
|
===== =========
|
||||||
|
|
||||||
|
For example, `u32` is a type whose valid values are all the 32-bit unsigned
|
||||||
|
numbers and `s16` is a types whose valid values are all the 16-bit signed
|
||||||
|
numbers.
|
||||||
|
|
||||||
|
Functions
|
||||||
|
---------
|
||||||
|
* `htobe16`: Takes an unsigned 16-bit number in host-endian format and
|
||||||
|
returns the equivalent number as an unsigned 16-bit number in big-endian
|
||||||
|
format.
|
||||||
|
* `htobe32`: Takes an unsigned 32-bit number in host-endian format and
|
||||||
|
returns the equivalent number as an unsigned 32-bit number in big-endian
|
||||||
|
format.
|
||||||
|
* `htobe64`: Takes an unsigned 64-bit number in host-endian format and
|
||||||
|
returns the equivalent number as an unsigned 64-bit number in big-endian
|
||||||
|
format.
|
||||||
|
* `htole16`: Takes an unsigned 16-bit number in host-endian format and
|
||||||
|
returns the equivalent number as an unsigned 16-bit number in little-endian
|
||||||
|
format.
|
||||||
|
* `htole32`: Takes an unsigned 32-bit number in host-endian format and
|
||||||
|
returns the equivalent number as an unsigned 32-bit number in little-endian
|
||||||
|
format.
|
||||||
|
* `htole64`: Takes an unsigned 64-bit number in host-endian format and
|
||||||
|
returns the equivalent number as an unsigned 64-bit number in little-endian
|
||||||
|
format.
|
||||||
|
* `bswap16`: Takes an unsigned 16-bit number in either big- or little-endian
|
||||||
|
format and returns the equivalent number with the same bit width but
|
||||||
|
opposite endianness.
|
||||||
|
* `bswap32`: Takes an unsigned 32-bit number in either big- or little-endian
|
||||||
|
format and returns the equivalent number with the same bit width but
|
||||||
|
opposite endianness.
|
||||||
|
* `bswap64`: Takes an unsigned 64-bit number in either big- or little-endian
|
||||||
|
format and returns the equivalent number with the same bit width but
|
||||||
|
opposite endianness.
|
||||||
|
|
||||||
|
|
||||||
|
Definitions
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. glossary::
|
||||||
|
|
||||||
|
Sign Extend
|
||||||
|
To `sign extend an` ``X`` `-bit number, A, to a` ``Y`` `-bit number, B ,` means to
|
||||||
|
|
||||||
|
#. Copy all ``X`` bits from `A` to the lower ``X`` bits of `B`.
|
||||||
|
#. Set the value of the remaining ``Y`` - ``X`` bits of `B` to the value of
|
||||||
|
the most-significant bit of `A`.
|
||||||
|
|
||||||
|
.. admonition:: Example
|
||||||
|
|
||||||
|
Sign extend an 8-bit number ``A`` to a 16-bit number ``B`` on a big-endian platform:
|
||||||
|
::
|
||||||
|
|
||||||
|
A: 10000110
|
||||||
|
B: 11111111 10000110
|
||||||
|
|
||||||
Registers and calling convention
|
Registers and calling convention
|
||||||
================================
|
================================
|
||||||
|
@ -172,7 +255,7 @@ BPF_SMOD 0x90 1 dst = (src != 0) ? (dst s% src) : dst
|
||||||
BPF_XOR 0xa0 0 dst ^= src
|
BPF_XOR 0xa0 0 dst ^= src
|
||||||
BPF_MOV 0xb0 0 dst = src
|
BPF_MOV 0xb0 0 dst = src
|
||||||
BPF_MOVSX 0xb0 8/16/32 dst = (s8,s16,s32)src
|
BPF_MOVSX 0xb0 8/16/32 dst = (s8,s16,s32)src
|
||||||
BPF_ARSH 0xc0 0 sign extending dst >>= (src & mask)
|
BPF_ARSH 0xc0 0 :term:`sign extending<Sign Extend>` dst >>= (src & mask)
|
||||||
BPF_END 0xd0 0 byte swap operations (see `Byte swap instructions`_ below)
|
BPF_END 0xd0 0 byte swap operations (see `Byte swap instructions`_ below)
|
||||||
========= ===== ======= ==========================================================
|
========= ===== ======= ==========================================================
|
||||||
|
|
||||||
|
@ -204,22 +287,22 @@ where '(u32)' indicates that the upper 32 bits are zeroed.
|
||||||
Note that most instructions have instruction offset of 0. Only three instructions
|
Note that most instructions have instruction offset of 0. Only three instructions
|
||||||
(``BPF_SDIV``, ``BPF_SMOD``, ``BPF_MOVSX``) have a non-zero offset.
|
(``BPF_SDIV``, ``BPF_SMOD``, ``BPF_MOVSX``) have a non-zero offset.
|
||||||
|
|
||||||
The devision and modulo operations support both unsigned and signed flavors.
|
The division and modulo operations support both unsigned and signed flavors.
|
||||||
|
|
||||||
For unsigned operations (``BPF_DIV`` and ``BPF_MOD``), for ``BPF_ALU``,
|
For unsigned operations (``BPF_DIV`` and ``BPF_MOD``), for ``BPF_ALU``,
|
||||||
'imm' is interpreted as a 32-bit unsigned value. For ``BPF_ALU64``,
|
'imm' is interpreted as a 32-bit unsigned value. For ``BPF_ALU64``,
|
||||||
'imm' is first sign extended from 32 to 64 bits, and then interpreted as
|
'imm' is first :term:`sign extended<Sign Extend>` from 32 to 64 bits, and then
|
||||||
a 64-bit unsigned value.
|
interpreted as a 64-bit unsigned value.
|
||||||
|
|
||||||
For signed operations (``BPF_SDIV`` and ``BPF_SMOD``), for ``BPF_ALU``,
|
For signed operations (``BPF_SDIV`` and ``BPF_SMOD``), for ``BPF_ALU``,
|
||||||
'imm' is interpreted as a 32-bit signed value. For ``BPF_ALU64``, 'imm'
|
'imm' is interpreted as a 32-bit signed value. For ``BPF_ALU64``, 'imm'
|
||||||
is first sign extended from 32 to 64 bits, and then interpreted as a
|
is first :term:`sign extended<Sign Extend>` from 32 to 64 bits, and then
|
||||||
64-bit signed value.
|
interpreted as a 64-bit signed value.
|
||||||
|
|
||||||
The ``BPF_MOVSX`` instruction does a move operation with sign extension.
|
The ``BPF_MOVSX`` instruction does a move operation with sign extension.
|
||||||
``BPF_ALU | BPF_MOVSX`` sign extends 8-bit and 16-bit operands into 32
|
``BPF_ALU | BPF_MOVSX`` :term:`sign extends<Sign Extend>` 8-bit and 16-bit operands into 32
|
||||||
bit operands, and zeroes the remaining upper 32 bits.
|
bit operands, and zeroes the remaining upper 32 bits.
|
||||||
``BPF_ALU64 | BPF_MOVSX`` sign extends 8-bit, 16-bit, and 32-bit
|
``BPF_ALU64 | BPF_MOVSX`` :term:`sign extends<Sign Extend>` 8-bit, 16-bit, and 32-bit
|
||||||
operands into 64 bit operands.
|
operands into 64 bit operands.
|
||||||
|
|
||||||
Shift operations use a mask of 0x3F (63) for 64-bit operations and 0x1F (31)
|
Shift operations use a mask of 0x3F (63) for 64-bit operations and 0x1F (31)
|
||||||
|
@ -252,19 +335,23 @@ are supported: 16, 32 and 64.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
``BPF_ALU | BPF_TO_LE | BPF_END`` with imm = 16 means::
|
``BPF_ALU | BPF_TO_LE | BPF_END`` with imm = 16/32/64 means::
|
||||||
|
|
||||||
dst = htole16(dst)
|
dst = htole16(dst)
|
||||||
|
dst = htole32(dst)
|
||||||
|
dst = htole64(dst)
|
||||||
|
|
||||||
``BPF_ALU | BPF_TO_BE | BPF_END`` with imm = 64 means::
|
``BPF_ALU | BPF_TO_BE | BPF_END`` with imm = 16/32/64 means::
|
||||||
|
|
||||||
|
dst = htobe16(dst)
|
||||||
|
dst = htobe32(dst)
|
||||||
dst = htobe64(dst)
|
dst = htobe64(dst)
|
||||||
|
|
||||||
``BPF_ALU64 | BPF_TO_LE | BPF_END`` with imm = 16/32/64 means::
|
``BPF_ALU64 | BPF_TO_LE | BPF_END`` with imm = 16/32/64 means::
|
||||||
|
|
||||||
dst = bswap16 dst
|
dst = bswap16(dst)
|
||||||
dst = bswap32 dst
|
dst = bswap32(dst)
|
||||||
dst = bswap64 dst
|
dst = bswap64(dst)
|
||||||
|
|
||||||
Jump instructions
|
Jump instructions
|
||||||
-----------------
|
-----------------
|
||||||
|
@ -400,7 +487,7 @@ Where size is one of: ``BPF_B``, ``BPF_H``, ``BPF_W``, or ``BPF_DW`` and
|
||||||
Sign-extension load operations
|
Sign-extension load operations
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
The ``BPF_MEMSX`` mode modifier is used to encode sign-extension load
|
The ``BPF_MEMSX`` mode modifier is used to encode :term:`sign-extension<Sign Extend>` load
|
||||||
instructions that transfer data between a register and memory.
|
instructions that transfer data between a register and memory.
|
||||||
|
|
||||||
``BPF_MEMSX | <size> | BPF_LDX`` means::
|
``BPF_MEMSX | <size> | BPF_LDX`` means::
|
||||||
|
|
|
@ -1819,6 +1819,7 @@ struct bpf_cg_run_ctx {
|
||||||
struct bpf_trace_run_ctx {
|
struct bpf_trace_run_ctx {
|
||||||
struct bpf_run_ctx run_ctx;
|
struct bpf_run_ctx run_ctx;
|
||||||
u64 bpf_cookie;
|
u64 bpf_cookie;
|
||||||
|
bool is_uprobe;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_tramp_run_ctx {
|
struct bpf_tramp_run_ctx {
|
||||||
|
@ -1867,6 +1868,8 @@ bpf_prog_run_array(const struct bpf_prog_array *array,
|
||||||
if (unlikely(!array))
|
if (unlikely(!array))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
run_ctx.is_uprobe = false;
|
||||||
|
|
||||||
migrate_disable();
|
migrate_disable();
|
||||||
old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx);
|
old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx);
|
||||||
item = &array->items[0];
|
item = &array->items[0];
|
||||||
|
@ -1891,8 +1894,8 @@ bpf_prog_run_array(const struct bpf_prog_array *array,
|
||||||
* rcu-protected dynamically sized maps.
|
* rcu-protected dynamically sized maps.
|
||||||
*/
|
*/
|
||||||
static __always_inline u32
|
static __always_inline u32
|
||||||
bpf_prog_run_array_sleepable(const struct bpf_prog_array __rcu *array_rcu,
|
bpf_prog_run_array_uprobe(const struct bpf_prog_array __rcu *array_rcu,
|
||||||
const void *ctx, bpf_prog_run_fn run_prog)
|
const void *ctx, bpf_prog_run_fn run_prog)
|
||||||
{
|
{
|
||||||
const struct bpf_prog_array_item *item;
|
const struct bpf_prog_array_item *item;
|
||||||
const struct bpf_prog *prog;
|
const struct bpf_prog *prog;
|
||||||
|
@ -1906,6 +1909,8 @@ bpf_prog_run_array_sleepable(const struct bpf_prog_array __rcu *array_rcu,
|
||||||
rcu_read_lock_trace();
|
rcu_read_lock_trace();
|
||||||
migrate_disable();
|
migrate_disable();
|
||||||
|
|
||||||
|
run_ctx.is_uprobe = true;
|
||||||
|
|
||||||
array = rcu_dereference_check(array_rcu, rcu_read_lock_trace_held());
|
array = rcu_dereference_check(array_rcu, rcu_read_lock_trace_held());
|
||||||
if (unlikely(!array))
|
if (unlikely(!array))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -204,8 +204,6 @@ u32 btf_nr_types(const struct btf *btf);
|
||||||
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
|
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
|
||||||
const struct btf_member *m,
|
const struct btf_member *m,
|
||||||
u32 expected_offset, u32 expected_size);
|
u32 expected_offset, u32 expected_size);
|
||||||
int btf_find_spin_lock(const struct btf *btf, const struct btf_type *t);
|
|
||||||
int btf_find_timer(const struct btf *btf, const struct btf_type *t);
|
|
||||||
struct btf_record *btf_parse_fields(const struct btf *btf, const struct btf_type *t,
|
struct btf_record *btf_parse_fields(const struct btf *btf, const struct btf_type *t,
|
||||||
u32 field_mask, u32 value_size);
|
u32 field_mask, u32 value_size);
|
||||||
int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec);
|
int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec);
|
||||||
|
|
|
@ -1572,10 +1572,9 @@ static inline void *bpf_xdp_pointer(struct xdp_buff *xdp, u32 offset, u32 len)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, void *buf,
|
static inline void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, void *buf,
|
||||||
unsigned long len, bool flush)
|
unsigned long len, bool flush)
|
||||||
{
|
{
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NET */
|
#endif /* CONFIG_NET */
|
||||||
|
|
||||||
|
|
|
@ -5086,9 +5086,14 @@ union bpf_attr {
|
||||||
* u64 bpf_get_func_ip(void *ctx)
|
* u64 bpf_get_func_ip(void *ctx)
|
||||||
* Description
|
* Description
|
||||||
* Get address of the traced function (for tracing and kprobe programs).
|
* Get address of the traced function (for tracing and kprobe programs).
|
||||||
|
*
|
||||||
|
* When called for kprobe program attached as uprobe it returns
|
||||||
|
* probe address for both entry and return uprobe.
|
||||||
|
*
|
||||||
* Return
|
* Return
|
||||||
* Address of the traced function.
|
* Address of the traced function for kprobe.
|
||||||
* 0 for kprobes placed within the function (not at the entry).
|
* 0 for kprobes placed within the function (not at the entry).
|
||||||
|
* Address of the probe for uprobe and return uprobe.
|
||||||
*
|
*
|
||||||
* u64 bpf_get_attach_cookie(void *ctx)
|
* u64 bpf_get_attach_cookie(void *ctx)
|
||||||
* Description
|
* Description
|
||||||
|
|
|
@ -75,6 +75,5 @@ void bpf_lru_populate(struct bpf_lru *lru, void *buf, u32 node_offset,
|
||||||
void bpf_lru_destroy(struct bpf_lru *lru);
|
void bpf_lru_destroy(struct bpf_lru *lru);
|
||||||
struct bpf_lru_node *bpf_lru_pop_free(struct bpf_lru *lru, u32 hash);
|
struct bpf_lru_node *bpf_lru_pop_free(struct bpf_lru *lru, u32 hash);
|
||||||
void bpf_lru_push_free(struct bpf_lru *lru, struct bpf_lru_node *node);
|
void bpf_lru_push_free(struct bpf_lru *lru, struct bpf_lru_node *node);
|
||||||
void bpf_lru_promote(struct bpf_lru *lru, struct bpf_lru_node *node);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -374,9 +374,9 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
|
||||||
struct bpf_struct_ops_value *uvalue, *kvalue;
|
struct bpf_struct_ops_value *uvalue, *kvalue;
|
||||||
const struct btf_member *member;
|
const struct btf_member *member;
|
||||||
const struct btf_type *t = st_ops->type;
|
const struct btf_type *t = st_ops->type;
|
||||||
struct bpf_tramp_links *tlinks = NULL;
|
struct bpf_tramp_links *tlinks;
|
||||||
void *udata, *kdata;
|
void *udata, *kdata;
|
||||||
int prog_fd, err = 0;
|
int prog_fd, err;
|
||||||
void *image, *image_end;
|
void *image, *image_end;
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
|
@ -815,7 +815,7 @@ static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map
|
||||||
struct bpf_struct_ops_map *st_map, *old_st_map;
|
struct bpf_struct_ops_map *st_map, *old_st_map;
|
||||||
struct bpf_map *old_map;
|
struct bpf_map *old_map;
|
||||||
struct bpf_struct_ops_link *st_link;
|
struct bpf_struct_ops_link *st_link;
|
||||||
int err = 0;
|
int err;
|
||||||
|
|
||||||
st_link = container_of(link, struct bpf_struct_ops_link, link);
|
st_link = container_of(link, struct bpf_struct_ops_link, link);
|
||||||
st_map = container_of(new_map, struct bpf_struct_ops_map, map);
|
st_map = container_of(new_map, struct bpf_struct_ops_map, map);
|
||||||
|
|
|
@ -87,12 +87,12 @@ const char *const bpf_alu_string[16] = {
|
||||||
[BPF_END >> 4] = "endian",
|
[BPF_END >> 4] = "endian",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *const bpf_alu_sign_string[16] = {
|
static const char *const bpf_alu_sign_string[16] = {
|
||||||
[BPF_DIV >> 4] = "s/=",
|
[BPF_DIV >> 4] = "s/=",
|
||||||
[BPF_MOD >> 4] = "s%=",
|
[BPF_MOD >> 4] = "s%=",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *const bpf_movsx_string[4] = {
|
static const char *const bpf_movsx_string[4] = {
|
||||||
[0] = "(s8)",
|
[0] = "(s8)",
|
||||||
[1] = "(s16)",
|
[1] = "(s16)",
|
||||||
[3] = "(s32)",
|
[3] = "(s32)",
|
||||||
|
|
|
@ -2270,7 +2270,7 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset
|
||||||
case BPF_DYNPTR_TYPE_XDP:
|
case BPF_DYNPTR_TYPE_XDP:
|
||||||
{
|
{
|
||||||
void *xdp_ptr = bpf_xdp_pointer(ptr->data, ptr->offset + offset, len);
|
void *xdp_ptr = bpf_xdp_pointer(ptr->data, ptr->offset + offset, len);
|
||||||
if (xdp_ptr)
|
if (!IS_ERR_OR_NULL(xdp_ptr))
|
||||||
return xdp_ptr;
|
return xdp_ptr;
|
||||||
|
|
||||||
if (!buffer__opt)
|
if (!buffer__opt)
|
||||||
|
|
|
@ -337,6 +337,8 @@ int bpf_mprog_detach(struct bpf_mprog_entry *entry,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (revision && revision != bpf_mprog_revision(entry))
|
if (revision && revision != bpf_mprog_revision(entry))
|
||||||
return -ESTALE;
|
return -ESTALE;
|
||||||
|
if (!bpf_mprog_total(entry))
|
||||||
|
return -ENOENT;
|
||||||
ret = bpf_mprog_tuple_relative(&rtuple, id_or_fd, flags,
|
ret = bpf_mprog_tuple_relative(&rtuple, id_or_fd, flags,
|
||||||
prog ? prog->type :
|
prog ? prog->type :
|
||||||
BPF_PROG_TYPE_UNSPEC);
|
BPF_PROG_TYPE_UNSPEC);
|
||||||
|
|
|
@ -13165,17 +13165,26 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
|
||||||
dst_reg->subreg_def = DEF_NOT_SUBREG;
|
dst_reg->subreg_def = DEF_NOT_SUBREG;
|
||||||
} else {
|
} else {
|
||||||
/* case: R1 = (s8, s16 s32)R2 */
|
/* case: R1 = (s8, s16 s32)R2 */
|
||||||
bool no_sext;
|
if (is_pointer_value(env, insn->src_reg)) {
|
||||||
|
verbose(env,
|
||||||
|
"R%d sign-extension part of pointer\n",
|
||||||
|
insn->src_reg);
|
||||||
|
return -EACCES;
|
||||||
|
} else if (src_reg->type == SCALAR_VALUE) {
|
||||||
|
bool no_sext;
|
||||||
|
|
||||||
no_sext = src_reg->umax_value < (1ULL << (insn->off - 1));
|
no_sext = src_reg->umax_value < (1ULL << (insn->off - 1));
|
||||||
if (no_sext && need_id)
|
if (no_sext && need_id)
|
||||||
src_reg->id = ++env->id_gen;
|
src_reg->id = ++env->id_gen;
|
||||||
copy_register_state(dst_reg, src_reg);
|
copy_register_state(dst_reg, src_reg);
|
||||||
if (!no_sext)
|
if (!no_sext)
|
||||||
dst_reg->id = 0;
|
dst_reg->id = 0;
|
||||||
coerce_reg_to_size_sx(dst_reg, insn->off >> 3);
|
coerce_reg_to_size_sx(dst_reg, insn->off >> 3);
|
||||||
dst_reg->live |= REG_LIVE_WRITTEN;
|
dst_reg->live |= REG_LIVE_WRITTEN;
|
||||||
dst_reg->subreg_def = DEF_NOT_SUBREG;
|
dst_reg->subreg_def = DEF_NOT_SUBREG;
|
||||||
|
} else {
|
||||||
|
mark_reg_unknown(env, regs, insn->dst_reg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* R1 = (u32) R2 */
|
/* R1 = (u32) R2 */
|
||||||
|
|
|
@ -1055,7 +1055,16 @@ static unsigned long get_entry_ip(unsigned long fentry_ip)
|
||||||
|
|
||||||
BPF_CALL_1(bpf_get_func_ip_kprobe, struct pt_regs *, regs)
|
BPF_CALL_1(bpf_get_func_ip_kprobe, struct pt_regs *, regs)
|
||||||
{
|
{
|
||||||
struct kprobe *kp = kprobe_running();
|
struct bpf_trace_run_ctx *run_ctx __maybe_unused;
|
||||||
|
struct kprobe *kp;
|
||||||
|
|
||||||
|
#ifdef CONFIG_UPROBES
|
||||||
|
run_ctx = container_of(current->bpf_ctx, struct bpf_trace_run_ctx, run_ctx);
|
||||||
|
if (run_ctx->is_uprobe)
|
||||||
|
return ((struct uprobe_dispatch_data *)current->utask->vaddr)->bp_addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
kp = kprobe_running();
|
||||||
|
|
||||||
if (!kp || !(kp->flags & KPROBE_FLAG_ON_FUNC_ENTRY))
|
if (!kp || !(kp->flags & KPROBE_FLAG_ON_FUNC_ENTRY))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -519,3 +519,8 @@ void __trace_probe_log_err(int offset, int err);
|
||||||
|
|
||||||
#define trace_probe_log_err(offs, err) \
|
#define trace_probe_log_err(offs, err) \
|
||||||
__trace_probe_log_err(offs, TP_ERR_##err)
|
__trace_probe_log_err(offs, TP_ERR_##err)
|
||||||
|
|
||||||
|
struct uprobe_dispatch_data {
|
||||||
|
struct trace_uprobe *tu;
|
||||||
|
unsigned long bp_addr;
|
||||||
|
};
|
||||||
|
|
|
@ -88,11 +88,6 @@ static struct trace_uprobe *to_trace_uprobe(struct dyn_event *ev)
|
||||||
static int register_uprobe_event(struct trace_uprobe *tu);
|
static int register_uprobe_event(struct trace_uprobe *tu);
|
||||||
static int unregister_uprobe_event(struct trace_uprobe *tu);
|
static int unregister_uprobe_event(struct trace_uprobe *tu);
|
||||||
|
|
||||||
struct uprobe_dispatch_data {
|
|
||||||
struct trace_uprobe *tu;
|
|
||||||
unsigned long bp_addr;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs);
|
static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs);
|
||||||
static int uretprobe_dispatcher(struct uprobe_consumer *con,
|
static int uretprobe_dispatcher(struct uprobe_consumer *con,
|
||||||
unsigned long func, struct pt_regs *regs);
|
unsigned long func, struct pt_regs *regs);
|
||||||
|
@ -1352,7 +1347,7 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
|
||||||
if (bpf_prog_array_valid(call)) {
|
if (bpf_prog_array_valid(call)) {
|
||||||
u32 ret;
|
u32 ret;
|
||||||
|
|
||||||
ret = bpf_prog_run_array_sleepable(call->prog_array, regs, bpf_prog_run);
|
ret = bpf_prog_run_array_uprobe(call->prog_array, regs, bpf_prog_run);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5086,9 +5086,14 @@ union bpf_attr {
|
||||||
* u64 bpf_get_func_ip(void *ctx)
|
* u64 bpf_get_func_ip(void *ctx)
|
||||||
* Description
|
* Description
|
||||||
* Get address of the traced function (for tracing and kprobe programs).
|
* Get address of the traced function (for tracing and kprobe programs).
|
||||||
|
*
|
||||||
|
* When called for kprobe program attached as uprobe it returns
|
||||||
|
* probe address for both entry and return uprobe.
|
||||||
|
*
|
||||||
* Return
|
* Return
|
||||||
* Address of the traced function.
|
* Address of the traced function for kprobe.
|
||||||
* 0 for kprobes placed within the function (not at the entry).
|
* 0 for kprobes placed within the function (not at the entry).
|
||||||
|
* Address of the probe for uprobe and return uprobe.
|
||||||
*
|
*
|
||||||
* u64 bpf_get_attach_cookie(void *ctx)
|
* u64 bpf_get_attach_cookie(void *ctx)
|
||||||
* Description
|
* Description
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#ifndef __BPF_TRACING_H__
|
#ifndef __BPF_TRACING_H__
|
||||||
#define __BPF_TRACING_H__
|
#define __BPF_TRACING_H__
|
||||||
|
|
||||||
#include <bpf/bpf_helpers.h>
|
#include "bpf_helpers.h"
|
||||||
|
|
||||||
/* Scan the ARCH passed in from ARCH env variable (see Makefile) */
|
/* Scan the ARCH passed in from ARCH env variable (see Makefile) */
|
||||||
#if defined(__TARGET_ARCH_x86)
|
#if defined(__TARGET_ARCH_x86)
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
#define __USDT_BPF_H__
|
#define __USDT_BPF_H__
|
||||||
|
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <bpf/bpf_helpers.h>
|
#include "bpf_helpers.h"
|
||||||
#include <bpf/bpf_tracing.h>
|
#include "bpf_tracing.h"
|
||||||
|
|
||||||
/* Below types and maps are internal implementation details of libbpf's USDT
|
/* Below types and maps are internal implementation details of libbpf's USDT
|
||||||
* support and are subjects to change. Also, bpf_usdt_xxx() API helpers should
|
* support and are subjects to change. Also, bpf_usdt_xxx() API helpers should
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "testing_helpers.h"
|
#include "testing_helpers.h"
|
||||||
#include "cgroup_tcp_skb.skel.h"
|
#include "cgroup_tcp_skb.skel.h"
|
||||||
#include "cgroup_tcp_skb.h"
|
#include "cgroup_tcp_skb.h"
|
||||||
|
#include "network_helpers.h"
|
||||||
|
|
||||||
#define CGROUP_TCP_SKB_PATH "/test_cgroup_tcp_skb"
|
#define CGROUP_TCP_SKB_PATH "/test_cgroup_tcp_skb"
|
||||||
|
|
||||||
|
@ -58,79 +59,13 @@ static int create_client_sock_v6(void)
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int create_server_sock_v6(void)
|
|
||||||
{
|
|
||||||
struct sockaddr_in6 addr = {
|
|
||||||
.sin6_family = AF_INET6,
|
|
||||||
.sin6_port = htons(0),
|
|
||||||
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
|
|
||||||
};
|
|
||||||
int fd, err;
|
|
||||||
|
|
||||||
fd = socket(AF_INET6, SOCK_STREAM, 0);
|
|
||||||
if (fd < 0) {
|
|
||||||
perror("socket");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
|
|
||||||
if (err < 0) {
|
|
||||||
perror("bind");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = listen(fd, 1);
|
|
||||||
if (err < 0) {
|
|
||||||
perror("listen");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_sock_port_v6(int fd)
|
|
||||||
{
|
|
||||||
struct sockaddr_in6 addr;
|
|
||||||
socklen_t len;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
len = sizeof(addr);
|
|
||||||
err = getsockname(fd, (struct sockaddr *)&addr, &len);
|
|
||||||
if (err < 0) {
|
|
||||||
perror("getsockname");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ntohs(addr.sin6_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int connect_client_server_v6(int client_fd, int listen_fd)
|
|
||||||
{
|
|
||||||
struct sockaddr_in6 addr = {
|
|
||||||
.sin6_family = AF_INET6,
|
|
||||||
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
|
|
||||||
};
|
|
||||||
int err;
|
|
||||||
|
|
||||||
addr.sin6_port = htons(get_sock_port_v6(listen_fd));
|
|
||||||
if (addr.sin6_port < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
err = connect(client_fd, (struct sockaddr *)&addr, sizeof(addr));
|
|
||||||
if (err < 0) {
|
|
||||||
perror("connect");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Connect to the server in a cgroup from the outside of the cgroup. */
|
/* Connect to the server in a cgroup from the outside of the cgroup. */
|
||||||
static int talk_to_cgroup(int *client_fd, int *listen_fd, int *service_fd,
|
static int talk_to_cgroup(int *client_fd, int *listen_fd, int *service_fd,
|
||||||
struct cgroup_tcp_skb *skel)
|
struct cgroup_tcp_skb *skel)
|
||||||
{
|
{
|
||||||
int err, cp;
|
int err, cp;
|
||||||
char buf[5];
|
char buf[5];
|
||||||
|
int port;
|
||||||
|
|
||||||
/* Create client & server socket */
|
/* Create client & server socket */
|
||||||
err = join_root_cgroup();
|
err = join_root_cgroup();
|
||||||
|
@ -142,14 +77,17 @@ static int talk_to_cgroup(int *client_fd, int *listen_fd, int *service_fd,
|
||||||
err = join_cgroup(CGROUP_TCP_SKB_PATH);
|
err = join_cgroup(CGROUP_TCP_SKB_PATH);
|
||||||
if (!ASSERT_OK(err, "join_cgroup"))
|
if (!ASSERT_OK(err, "join_cgroup"))
|
||||||
return -1;
|
return -1;
|
||||||
*listen_fd = create_server_sock_v6();
|
*listen_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
|
||||||
if (!ASSERT_GE(*listen_fd, 0, "listen_fd"))
|
if (!ASSERT_GE(*listen_fd, 0, "listen_fd"))
|
||||||
return -1;
|
return -1;
|
||||||
skel->bss->g_sock_port = get_sock_port_v6(*listen_fd);
|
port = get_socket_local_port(*listen_fd);
|
||||||
|
if (!ASSERT_GE(port, 0, "get_socket_local_port"))
|
||||||
|
return -1;
|
||||||
|
skel->bss->g_sock_port = ntohs(port);
|
||||||
|
|
||||||
/* Connect client to server */
|
/* Connect client to server */
|
||||||
err = connect_client_server_v6(*client_fd, *listen_fd);
|
err = connect_fd_to_fd(*client_fd, *listen_fd, 0);
|
||||||
if (!ASSERT_OK(err, "connect_client_server_v6"))
|
if (!ASSERT_OK(err, "connect_fd_to_fd"))
|
||||||
return -1;
|
return -1;
|
||||||
*service_fd = accept(*listen_fd, NULL, NULL);
|
*service_fd = accept(*listen_fd, NULL, NULL);
|
||||||
if (!ASSERT_GE(*service_fd, 0, "service_fd"))
|
if (!ASSERT_GE(*service_fd, 0, "service_fd"))
|
||||||
|
@ -174,12 +112,13 @@ static int talk_to_outside(int *client_fd, int *listen_fd, int *service_fd,
|
||||||
{
|
{
|
||||||
int err, cp;
|
int err, cp;
|
||||||
char buf[5];
|
char buf[5];
|
||||||
|
int port;
|
||||||
|
|
||||||
/* Create client & server socket */
|
/* Create client & server socket */
|
||||||
err = join_root_cgroup();
|
err = join_root_cgroup();
|
||||||
if (!ASSERT_OK(err, "join_root_cgroup"))
|
if (!ASSERT_OK(err, "join_root_cgroup"))
|
||||||
return -1;
|
return -1;
|
||||||
*listen_fd = create_server_sock_v6();
|
*listen_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
|
||||||
if (!ASSERT_GE(*listen_fd, 0, "listen_fd"))
|
if (!ASSERT_GE(*listen_fd, 0, "listen_fd"))
|
||||||
return -1;
|
return -1;
|
||||||
err = join_cgroup(CGROUP_TCP_SKB_PATH);
|
err = join_cgroup(CGROUP_TCP_SKB_PATH);
|
||||||
|
@ -191,11 +130,14 @@ static int talk_to_outside(int *client_fd, int *listen_fd, int *service_fd,
|
||||||
err = join_root_cgroup();
|
err = join_root_cgroup();
|
||||||
if (!ASSERT_OK(err, "join_root_cgroup"))
|
if (!ASSERT_OK(err, "join_root_cgroup"))
|
||||||
return -1;
|
return -1;
|
||||||
skel->bss->g_sock_port = get_sock_port_v6(*listen_fd);
|
port = get_socket_local_port(*listen_fd);
|
||||||
|
if (!ASSERT_GE(port, 0, "get_socket_local_port"))
|
||||||
|
return -1;
|
||||||
|
skel->bss->g_sock_port = ntohs(port);
|
||||||
|
|
||||||
/* Connect client to server */
|
/* Connect client to server */
|
||||||
err = connect_client_server_v6(*client_fd, *listen_fd);
|
err = connect_fd_to_fd(*client_fd, *listen_fd, 0);
|
||||||
if (!ASSERT_OK(err, "connect_client_server_v6"))
|
if (!ASSERT_OK(err, "connect_fd_to_fd"))
|
||||||
return -1;
|
return -1;
|
||||||
*service_fd = accept(*listen_fd, NULL, NULL);
|
*service_fd = accept(*listen_fd, NULL, NULL);
|
||||||
if (!ASSERT_GE(*service_fd, 0, "service_fd"))
|
if (!ASSERT_GE(*service_fd, 0, "service_fd"))
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <test_progs.h>
|
#include <test_progs.h>
|
||||||
#include "get_func_ip_test.skel.h"
|
#include "get_func_ip_test.skel.h"
|
||||||
|
#include "get_func_ip_uprobe_test.skel.h"
|
||||||
|
|
||||||
|
static noinline void uprobe_trigger(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static void test_function_entry(void)
|
static void test_function_entry(void)
|
||||||
{
|
{
|
||||||
|
@ -20,6 +25,8 @@ static void test_function_entry(void)
|
||||||
if (!ASSERT_OK(err, "get_func_ip_test__attach"))
|
if (!ASSERT_OK(err, "get_func_ip_test__attach"))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
skel->bss->uprobe_trigger = (unsigned long) uprobe_trigger;
|
||||||
|
|
||||||
prog_fd = bpf_program__fd(skel->progs.test1);
|
prog_fd = bpf_program__fd(skel->progs.test1);
|
||||||
err = bpf_prog_test_run_opts(prog_fd, &topts);
|
err = bpf_prog_test_run_opts(prog_fd, &topts);
|
||||||
ASSERT_OK(err, "test_run");
|
ASSERT_OK(err, "test_run");
|
||||||
|
@ -30,21 +37,31 @@ static void test_function_entry(void)
|
||||||
|
|
||||||
ASSERT_OK(err, "test_run");
|
ASSERT_OK(err, "test_run");
|
||||||
|
|
||||||
|
uprobe_trigger();
|
||||||
|
|
||||||
ASSERT_EQ(skel->bss->test1_result, 1, "test1_result");
|
ASSERT_EQ(skel->bss->test1_result, 1, "test1_result");
|
||||||
ASSERT_EQ(skel->bss->test2_result, 1, "test2_result");
|
ASSERT_EQ(skel->bss->test2_result, 1, "test2_result");
|
||||||
ASSERT_EQ(skel->bss->test3_result, 1, "test3_result");
|
ASSERT_EQ(skel->bss->test3_result, 1, "test3_result");
|
||||||
ASSERT_EQ(skel->bss->test4_result, 1, "test4_result");
|
ASSERT_EQ(skel->bss->test4_result, 1, "test4_result");
|
||||||
ASSERT_EQ(skel->bss->test5_result, 1, "test5_result");
|
ASSERT_EQ(skel->bss->test5_result, 1, "test5_result");
|
||||||
|
ASSERT_EQ(skel->bss->test7_result, 1, "test7_result");
|
||||||
|
ASSERT_EQ(skel->bss->test8_result, 1, "test8_result");
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
get_func_ip_test__destroy(skel);
|
get_func_ip_test__destroy(skel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* test6 is x86_64 specific because of the instruction
|
|
||||||
* offset, disabling it for all other archs
|
|
||||||
*/
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
static void test_function_body(void)
|
extern void uprobe_trigger_body(void);
|
||||||
|
asm(
|
||||||
|
".globl uprobe_trigger_body\n"
|
||||||
|
".type uprobe_trigger_body, @function\n"
|
||||||
|
"uprobe_trigger_body:\n"
|
||||||
|
" nop\n"
|
||||||
|
" ret\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
static void test_function_body_kprobe(void)
|
||||||
{
|
{
|
||||||
struct get_func_ip_test *skel = NULL;
|
struct get_func_ip_test *skel = NULL;
|
||||||
LIBBPF_OPTS(bpf_test_run_opts, topts);
|
LIBBPF_OPTS(bpf_test_run_opts, topts);
|
||||||
|
@ -56,6 +73,9 @@ static void test_function_body(void)
|
||||||
if (!ASSERT_OK_PTR(skel, "get_func_ip_test__open"))
|
if (!ASSERT_OK_PTR(skel, "get_func_ip_test__open"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* test6 is x86_64 specific and is disabled by default,
|
||||||
|
* enable it for body test.
|
||||||
|
*/
|
||||||
bpf_program__set_autoload(skel->progs.test6, true);
|
bpf_program__set_autoload(skel->progs.test6, true);
|
||||||
|
|
||||||
err = get_func_ip_test__load(skel);
|
err = get_func_ip_test__load(skel);
|
||||||
|
@ -79,6 +99,35 @@ cleanup:
|
||||||
bpf_link__destroy(link6);
|
bpf_link__destroy(link6);
|
||||||
get_func_ip_test__destroy(skel);
|
get_func_ip_test__destroy(skel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_function_body_uprobe(void)
|
||||||
|
{
|
||||||
|
struct get_func_ip_uprobe_test *skel = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
skel = get_func_ip_uprobe_test__open_and_load();
|
||||||
|
if (!ASSERT_OK_PTR(skel, "get_func_ip_uprobe_test__open_and_load"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
err = get_func_ip_uprobe_test__attach(skel);
|
||||||
|
if (!ASSERT_OK(err, "get_func_ip_test__attach"))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
skel->bss->uprobe_trigger_body = (unsigned long) uprobe_trigger_body;
|
||||||
|
|
||||||
|
uprobe_trigger_body();
|
||||||
|
|
||||||
|
ASSERT_EQ(skel->bss->test1_result, 1, "test1_result");
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
get_func_ip_uprobe_test__destroy(skel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_function_body(void)
|
||||||
|
{
|
||||||
|
test_function_body_kprobe();
|
||||||
|
test_function_body_uprobe();
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#define test_function_body()
|
#define test_function_body()
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -124,7 +124,7 @@ static void missing_map(void)
|
||||||
ASSERT_FALSE(bpf_map__autocreate(skel->maps.missing_map), "missing_map_autocreate");
|
ASSERT_FALSE(bpf_map__autocreate(skel->maps.missing_map), "missing_map_autocreate");
|
||||||
|
|
||||||
ASSERT_HAS_SUBSTR(log_buf,
|
ASSERT_HAS_SUBSTR(log_buf,
|
||||||
"8: <invalid BPF map reference>\n"
|
": <invalid BPF map reference>\n"
|
||||||
"BPF map 'missing_map' is referenced but wasn't created\n",
|
"BPF map 'missing_map' is referenced but wasn't created\n",
|
||||||
"log_buf");
|
"log_buf");
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include <regex.h>
|
||||||
#include <test_progs.h>
|
#include <test_progs.h>
|
||||||
#include <network_helpers.h>
|
#include <network_helpers.h>
|
||||||
|
|
||||||
|
@ -19,12 +20,16 @@ static struct {
|
||||||
"; R1_w=map_value(off=0,ks=4,vs=4,imm=0)\n2: (85) call bpf_this_cpu_ptr#154\n"
|
"; R1_w=map_value(off=0,ks=4,vs=4,imm=0)\n2: (85) call bpf_this_cpu_ptr#154\n"
|
||||||
"R1 type=map_value expected=percpu_ptr_" },
|
"R1 type=map_value expected=percpu_ptr_" },
|
||||||
{ "lock_id_mapval_preserve",
|
{ "lock_id_mapval_preserve",
|
||||||
"8: (bf) r1 = r0 ; R0_w=map_value(id=1,off=0,ks=4,vs=8,imm=0) "
|
"[0-9]\\+: (bf) r1 = r0 ;"
|
||||||
"R1_w=map_value(id=1,off=0,ks=4,vs=8,imm=0)\n9: (85) call bpf_this_cpu_ptr#154\n"
|
" R0_w=map_value(id=1,off=0,ks=4,vs=8,imm=0)"
|
||||||
|
" R1_w=map_value(id=1,off=0,ks=4,vs=8,imm=0)\n"
|
||||||
|
"[0-9]\\+: (85) call bpf_this_cpu_ptr#154\n"
|
||||||
"R1 type=map_value expected=percpu_ptr_" },
|
"R1 type=map_value expected=percpu_ptr_" },
|
||||||
{ "lock_id_innermapval_preserve",
|
{ "lock_id_innermapval_preserve",
|
||||||
"13: (bf) r1 = r0 ; R0=map_value(id=2,off=0,ks=4,vs=8,imm=0) "
|
"[0-9]\\+: (bf) r1 = r0 ;"
|
||||||
"R1_w=map_value(id=2,off=0,ks=4,vs=8,imm=0)\n14: (85) call bpf_this_cpu_ptr#154\n"
|
" R0=map_value(id=2,off=0,ks=4,vs=8,imm=0)"
|
||||||
|
" R1_w=map_value(id=2,off=0,ks=4,vs=8,imm=0)\n"
|
||||||
|
"[0-9]\\+: (85) call bpf_this_cpu_ptr#154\n"
|
||||||
"R1 type=map_value expected=percpu_ptr_" },
|
"R1 type=map_value expected=percpu_ptr_" },
|
||||||
{ "lock_id_mismatch_kptr_kptr", "bpf_spin_unlock of different lock" },
|
{ "lock_id_mismatch_kptr_kptr", "bpf_spin_unlock of different lock" },
|
||||||
{ "lock_id_mismatch_kptr_global", "bpf_spin_unlock of different lock" },
|
{ "lock_id_mismatch_kptr_global", "bpf_spin_unlock of different lock" },
|
||||||
|
@ -45,6 +50,24 @@ static struct {
|
||||||
{ "lock_id_mismatch_innermapval_mapval", "bpf_spin_unlock of different lock" },
|
{ "lock_id_mismatch_innermapval_mapval", "bpf_spin_unlock of different lock" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int match_regex(const char *pattern, const char *string)
|
||||||
|
{
|
||||||
|
int err, rc;
|
||||||
|
regex_t re;
|
||||||
|
|
||||||
|
err = regcomp(&re, pattern, REG_NOSUB);
|
||||||
|
if (err) {
|
||||||
|
char errbuf[512];
|
||||||
|
|
||||||
|
regerror(err, &re, errbuf, sizeof(errbuf));
|
||||||
|
PRINT_FAIL("Can't compile regex: %s\n", errbuf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
rc = regexec(&re, string, 0, NULL, 0);
|
||||||
|
regfree(&re);
|
||||||
|
return rc == 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void test_spin_lock_fail_prog(const char *prog_name, const char *err_msg)
|
static void test_spin_lock_fail_prog(const char *prog_name, const char *err_msg)
|
||||||
{
|
{
|
||||||
LIBBPF_OPTS(bpf_object_open_opts, opts, .kernel_log_buf = log_buf,
|
LIBBPF_OPTS(bpf_object_open_opts, opts, .kernel_log_buf = log_buf,
|
||||||
|
@ -74,7 +97,11 @@ static void test_spin_lock_fail_prog(const char *prog_name, const char *err_msg)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ASSERT_OK_PTR(strstr(log_buf, err_msg), "expected error message")) {
|
ret = match_regex(err_msg, log_buf);
|
||||||
|
if (!ASSERT_GE(ret, 0, "match_regex"))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (!ASSERT_TRUE(ret, "no match for expected error message")) {
|
||||||
fprintf(stderr, "Expected: %s\n", err_msg);
|
fprintf(stderr, "Expected: %s\n", err_msg);
|
||||||
fprintf(stderr, "Verifier: %s\n", log_buf);
|
fprintf(stderr, "Verifier: %s\n", log_buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2237,3 +2237,34 @@ void serial_test_tc_opts_detach_after(void)
|
||||||
test_tc_opts_detach_after_target(BPF_TCX_INGRESS);
|
test_tc_opts_detach_after_target(BPF_TCX_INGRESS);
|
||||||
test_tc_opts_detach_after_target(BPF_TCX_EGRESS);
|
test_tc_opts_detach_after_target(BPF_TCX_EGRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_tc_opts_delete_empty(int target, bool chain_tc_old)
|
||||||
|
{
|
||||||
|
LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
|
||||||
|
LIBBPF_OPTS(bpf_prog_detach_opts, optd);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
assert_mprog_count(target, 0);
|
||||||
|
if (chain_tc_old) {
|
||||||
|
tc_hook.attach_point = target == BPF_TCX_INGRESS ?
|
||||||
|
BPF_TC_INGRESS : BPF_TC_EGRESS;
|
||||||
|
err = bpf_tc_hook_create(&tc_hook);
|
||||||
|
ASSERT_OK(err, "bpf_tc_hook_create");
|
||||||
|
__assert_mprog_count(target, 0, true, loopback);
|
||||||
|
}
|
||||||
|
err = bpf_prog_detach_opts(0, loopback, target, &optd);
|
||||||
|
ASSERT_EQ(err, -ENOENT, "prog_detach");
|
||||||
|
if (chain_tc_old) {
|
||||||
|
tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
|
||||||
|
bpf_tc_hook_destroy(&tc_hook);
|
||||||
|
}
|
||||||
|
assert_mprog_count(target, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void serial_test_tc_opts_delete_empty(void)
|
||||||
|
{
|
||||||
|
test_tc_opts_delete_empty(BPF_TCX_INGRESS, false);
|
||||||
|
test_tc_opts_delete_empty(BPF_TCX_EGRESS, false);
|
||||||
|
test_tc_opts_delete_empty(BPF_TCX_INGRESS, true);
|
||||||
|
test_tc_opts_delete_empty(BPF_TCX_EGRESS, true);
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <linux/bpf.h>
|
#include "vmlinux.h"
|
||||||
#include <bpf/bpf_helpers.h>
|
#include <bpf/bpf_helpers.h>
|
||||||
#include <bpf/bpf_tracing.h>
|
#include <bpf/bpf_tracing.h>
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
char _license[] SEC("license") = "GPL";
|
char _license[] SEC("license") = "GPL";
|
||||||
|
|
||||||
|
@ -83,3 +82,25 @@ int test6(struct pt_regs *ctx)
|
||||||
test6_result = (const void *) addr == 0;
|
test6_result = (const void *) addr == 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long uprobe_trigger;
|
||||||
|
|
||||||
|
__u64 test7_result = 0;
|
||||||
|
SEC("uprobe//proc/self/exe:uprobe_trigger")
|
||||||
|
int BPF_UPROBE(test7)
|
||||||
|
{
|
||||||
|
__u64 addr = bpf_get_func_ip(ctx);
|
||||||
|
|
||||||
|
test7_result = (const void *) addr == (const void *) uprobe_trigger;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__u64 test8_result = 0;
|
||||||
|
SEC("uretprobe//proc/self/exe:uprobe_trigger")
|
||||||
|
int BPF_URETPROBE(test8, int ret)
|
||||||
|
{
|
||||||
|
__u64 addr = bpf_get_func_ip(ctx);
|
||||||
|
|
||||||
|
test8_result = (const void *) addr == (const void *) uprobe_trigger;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
18
tools/testing/selftests/bpf/progs/get_func_ip_uprobe_test.c
Normal file
18
tools/testing/selftests/bpf/progs/get_func_ip_uprobe_test.c
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include "vmlinux.h"
|
||||||
|
#include <bpf/bpf_helpers.h>
|
||||||
|
#include <bpf/bpf_tracing.h>
|
||||||
|
|
||||||
|
char _license[] SEC("license") = "GPL";
|
||||||
|
|
||||||
|
unsigned long uprobe_trigger_body;
|
||||||
|
|
||||||
|
__u64 test1_result = 0;
|
||||||
|
SEC("uprobe//proc/self/exe:uprobe_trigger_body+1")
|
||||||
|
int BPF_UPROBE(test1)
|
||||||
|
{
|
||||||
|
__u64 addr = bpf_get_func_ip(ctx);
|
||||||
|
|
||||||
|
test1_result = (const void *) addr == (const void *) uprobe_trigger_body + 1;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -198,6 +198,28 @@ l0_%=: \
|
||||||
: __clobber_all);
|
: __clobber_all);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SEC("socket")
|
||||||
|
__description("MOV64SX, S16, R10 Sign Extension")
|
||||||
|
__failure __msg("R1 type=scalar expected=fp, pkt, pkt_meta, map_key, map_value, mem, ringbuf_mem, buf, trusted_ptr_")
|
||||||
|
__failure_unpriv __msg_unpriv("R10 sign-extension part of pointer")
|
||||||
|
__naked void mov64sx_s16_r10(void)
|
||||||
|
{
|
||||||
|
asm volatile (" \
|
||||||
|
r1 = 553656332; \
|
||||||
|
*(u32 *)(r10 - 8) = r1; \
|
||||||
|
r1 = (s16)r10; \
|
||||||
|
r1 += -8; \
|
||||||
|
r2 = 3; \
|
||||||
|
if r2 <= r1 goto l0_%=; \
|
||||||
|
l0_%=: \
|
||||||
|
call %[bpf_trace_printk]; \
|
||||||
|
r0 = 0; \
|
||||||
|
exit; \
|
||||||
|
" :
|
||||||
|
: __imm(bpf_trace_printk)
|
||||||
|
: __clobber_all);
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
SEC("socket")
|
SEC("socket")
|
||||||
|
|
Loading…
Add table
Reference in a new issue