mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Daniel Borkmann says:
====================
pull-request: bpf-next 2022-06-17
We've added 72 non-merge commits during the last 15 day(s) which contain
a total of 92 files changed, 4582 insertions(+), 834 deletions(-).
The main changes are:
1) Add 64 bit enum value support to BTF, from Yonghong Song.
2) Implement support for sleepable BPF uprobe programs, from Delyan Kratunov.
3) Add new BPF helpers to issue and check TCP SYN cookies without binding to a
socket especially useful in synproxy scenarios, from Maxim Mikityanskiy.
4) Fix libbpf's internal USDT address translation logic for shared libraries as
well as uprobe's symbol file offset calculation, from Andrii Nakryiko.
5) Extend libbpf to provide an API for textual representation of the various
map/prog/attach/link types and use it in bpftool, from Daniel Müller.
6) Provide BTF line info for RV64 and RV32 JITs, and fix a put_user bug in the
core seen in 32 bit when storing BPF function addresses, from Pu Lehui.
7) Fix libbpf's BTF pointer size guessing by adding a list of various aliases
for 'long' types, from Douglas Raillard.
8) Fix bpftool to readd setting rlimit since probing for memcg-based accounting
has been unreliable and caused a regression on COS, from Quentin Monnet.
9) Fix UAF in BPF cgroup's effective program computation triggered upon BPF link
detachment, from Tadeusz Struk.
10) Fix bpftool build bootstrapping during cross compilation which was pointing
to the wrong AR process, from Shahab Vahedi.
11) Fix logic bug in libbpf's is_pow_of_2 implementation, from Yuze Chi.
12) BPF hash map optimization to avoid grabbing spinlocks of all CPUs when there
is no free element. Also add a benchmark as reproducer, from Feng Zhou.
13) Fix bpftool's codegen to bail out when there's no BTF, from Michael Mullin.
14) Various minor cleanup and improvements all over the place.
* https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next: (72 commits)
bpf: Fix bpf_skc_lookup comment wrt. return type
bpf: Fix non-static bpf_func_proto struct definitions
selftests/bpf: Don't force lld on non-x86 architectures
selftests/bpf: Add selftests for raw syncookie helpers in TC mode
bpf: Allow the new syncookie helpers to work with SKBs
selftests/bpf: Add selftests for raw syncookie helpers
bpf: Add helpers to issue and check SYN cookies in XDP
bpf: Allow helpers to accept pointers with a fixed size
bpf: Fix documentation of th_len in bpf_tcp_{gen,check}_syncookie
selftests/bpf: add tests for sleepable (uk)probes
libbpf: add support for sleepable uprobe programs
bpf: allow sleepable uprobe programs to attach
bpf: implement sleepable uprobes by chaining gps
bpf: move bpf_prog to bpf.h
libbpf: Fix internal USDT address translation logic for shared libraries
samples/bpf: Check detach prog exist or not in xdp_fwd
selftests/bpf: Avoid skipping certain subtests
selftests/bpf: Fix test_varlen verification failure with latest llvm
bpftool: Do not check return value from libbpf_set_strict_mode()
Revert "bpftool: Use libbpf 1.0 API mode instead of RLIMIT_MEMLOCK"
...
====================
Link: https://lore.kernel.org/r/20220617220836.7373-1-daniel@iogearbox.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
9fb424c4c2
92 files changed
+4583
-835
No files matched your search
@@ -74,7 +74,7 @@ sequentially and type id is assigned to each recognized type starting from id
|
||||
#define BTF_KIND_ARRAY 3 /* Array */
|
||||
#define BTF_KIND_STRUCT 4 /* Struct */
|
||||
#define BTF_KIND_UNION 5 /* Union */
|
||||
#define BTF_KIND_ENUM 6 /* Enumeration */
|
||||
#define BTF_KIND_ENUM 6 /* Enumeration up to 32-bit values */
|
||||
#define BTF_KIND_FWD 7 /* Forward */
|
||||
#define BTF_KIND_TYPEDEF 8 /* Typedef */
|
||||
#define BTF_KIND_VOLATILE 9 /* Volatile */
|
||||
@@ -87,6 +87,7 @@ sequentially and type id is assigned to each recognized type starting from id
|
||||
#define BTF_KIND_FLOAT 16 /* Floating point */
|
||||
#define BTF_KIND_DECL_TAG 17 /* Decl Tag */
|
||||
#define BTF_KIND_TYPE_TAG 18 /* Type Tag */
|
||||
#define BTF_KIND_ENUM64 19 /* Enumeration up to 64-bit values */
|
||||
|
||||
Note that the type section encodes debug info, not just pure types.
|
||||
``BTF_KIND_FUNC`` is not a type, and it represents a defined subprogram.
|
||||
@@ -101,10 +102,10 @@ Each type contains the following common data::
|
||||
* bits 24-28: kind (e.g. int, ptr, array...etc)
|
||||
* bits 29-30: unused
|
||||
* bit 31: kind_flag, currently used by
|
||||
* struct, union and fwd
|
||||
* struct, union, fwd, enum and enum64.
|
||||
*/
|
||||
__u32 info;
|
||||
/* "size" is used by INT, ENUM, STRUCT and UNION.
|
||||
/* "size" is used by INT, ENUM, STRUCT, UNION and ENUM64.
|
||||
* "size" tells the size of the type it is describing.
|
||||
*
|
||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
||||
@@ -281,10 +282,10 @@ modes exist:
|
||||
|
||||
``struct btf_type`` encoding requirement:
|
||||
* ``name_off``: 0 or offset to a valid C identifier
|
||||
* ``info.kind_flag``: 0
|
||||
* ``info.kind_flag``: 0 for unsigned, 1 for signed
|
||||
* ``info.kind``: BTF_KIND_ENUM
|
||||
* ``info.vlen``: number of enum values
|
||||
* ``size``: 4
|
||||
* ``size``: 1/2/4/8
|
||||
|
||||
``btf_type`` is followed by ``info.vlen`` number of ``struct btf_enum``.::
|
||||
|
||||
@@ -297,6 +298,10 @@ The ``btf_enum`` encoding:
|
||||
* ``name_off``: offset to a valid C identifier
|
||||
* ``val``: any value
|
||||
|
||||
If the original enum value is signed and the size is less than 4,
|
||||
that value will be sign extended into 4 bytes. If the size is 8,
|
||||
the value will be truncated into 4 bytes.
|
||||
|
||||
2.2.7 BTF_KIND_FWD
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -493,7 +498,7 @@ the attribute is applied to a ``struct``/``union`` member or
|
||||
a ``func`` argument, and ``btf_decl_tag.component_idx`` should be a
|
||||
valid index (starting from 0) pointing to a member or an argument.
|
||||
|
||||
2.2.17 BTF_KIND_TYPE_TAG
|
||||
2.2.18 BTF_KIND_TYPE_TAG
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``struct btf_type`` encoding requirement:
|
||||
@@ -516,6 +521,32 @@ type_tag, then zero or more const/volatile/restrict/typedef
|
||||
and finally the base type. The base type is one of
|
||||
int, ptr, array, struct, union, enum, func_proto and float types.
|
||||
|
||||
2.2.19 BTF_KIND_ENUM64
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``struct btf_type`` encoding requirement:
|
||||
* ``name_off``: 0 or offset to a valid C identifier
|
||||
* ``info.kind_flag``: 0 for unsigned, 1 for signed
|
||||
* ``info.kind``: BTF_KIND_ENUM64
|
||||
* ``info.vlen``: number of enum values
|
||||
* ``size``: 1/2/4/8
|
||||
|
||||
``btf_type`` is followed by ``info.vlen`` number of ``struct btf_enum64``.::
|
||||
|
||||
struct btf_enum64 {
|
||||
__u32 name_off;
|
||||
__u32 val_lo32;
|
||||
__u32 val_hi32;
|
||||
};
|
||||
|
||||
The ``btf_enum64`` encoding:
|
||||
* ``name_off``: offset to a valid C identifier
|
||||
* ``val_lo32``: lower 32-bit value for a 64-bit value
|
||||
* ``val_hi32``: high 32-bit value for a 64-bit value
|
||||
|
||||
If the original enum value is signed and the size is less than 8,
|
||||
that value will be sign extended into 8 bytes.
|
||||
|
||||
3. BTF Kernel API
|
||||
=================
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ BPF_XOR | BPF_K | BPF_ALU64 means::
|
||||
Byte swap instructions
|
||||
----------------------
|
||||
|
||||
The byte swap instructions use an instruction class of ``BFP_ALU`` and a 4-bit
|
||||
The byte swap instructions use an instruction class of ``BPF_ALU`` and a 4-bit
|
||||
code field of ``BPF_END``.
|
||||
|
||||
The byte swap instructions operate on the destination register
|
||||
|
||||
@@ -712,22 +712,6 @@ static inline void emit_alu_r(const u8 dst, const u8 src, const bool is64,
|
||||
}
|
||||
}
|
||||
|
||||
/* ALU operation (32 bit)
|
||||
* dst = dst (op) src
|
||||
*/
|
||||
static inline void emit_a32_alu_r(const s8 dst, const s8 src,
|
||||
struct jit_ctx *ctx, const bool is64,
|
||||
const bool hi, const u8 op) {
|
||||
const s8 *tmp = bpf2a32[TMP_REG_1];
|
||||
s8 rn, rd;
|
||||
|
||||
rn = arm_bpf_get_reg32(src, tmp[1], ctx);
|
||||
rd = arm_bpf_get_reg32(dst, tmp[0], ctx);
|
||||
/* ALU operation */
|
||||
emit_alu_r(rd, rn, is64, hi, op, ctx);
|
||||
arm_bpf_put_reg32(dst, rd, ctx);
|
||||
}
|
||||
|
||||
/* ALU operation (64 bit) */
|
||||
static inline void emit_a32_alu_r64(const bool is64, const s8 dst[],
|
||||
const s8 src[], struct jit_ctx *ctx,
|
||||
|
||||
@@ -69,6 +69,7 @@ struct rv_jit_context {
|
||||
struct bpf_prog *prog;
|
||||
u16 *insns; /* RV insns */
|
||||
int ninsns;
|
||||
int body_len;
|
||||
int epilogue_offset;
|
||||
int *offset; /* BPF to RV */
|
||||
int nexentries;
|
||||
|
||||
@@ -44,7 +44,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
unsigned int prog_size = 0, extable_size = 0;
|
||||
bool tmp_blinded = false, extra_pass = false;
|
||||
struct bpf_prog *tmp, *orig_prog = prog;
|
||||
int pass = 0, prev_ninsns = 0, i;
|
||||
int pass = 0, prev_ninsns = 0, prologue_len, i;
|
||||
struct rv_jit_data *jit_data;
|
||||
struct rv_jit_context *ctx;
|
||||
|
||||
@@ -95,6 +95,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
||||
prog = orig_prog;
|
||||
goto out_offset;
|
||||
}
|
||||
ctx->body_len = ctx->ninsns;
|
||||
bpf_jit_build_prologue(ctx);
|
||||
ctx->epilogue_offset = ctx->ninsns;
|
||||
bpf_jit_build_epilogue(ctx);
|
||||
@@ -161,6 +162,11 @@ skip_init_ctx:
|
||||
|
||||
if (!prog->is_func || extra_pass) {
|
||||
bpf_jit_binary_lock_ro(jit_data->header);
|
||||
prologue_len = ctx->epilogue_offset - ctx->body_len;
|
||||
for (i = 0; i < prog->len; i++)
|
||||
ctx->offset[i] = ninsns_rvoff(prologue_len +
|
||||
ctx->offset[i]);
|
||||
bpf_prog_fill_jited_linfo(prog, ctx->offset);
|
||||
out_offset:
|
||||
kfree(ctx->offset);
|
||||
kfree(jit_data);
|
||||
|
||||
+102
-3
@@ -5,6 +5,7 @@
|
||||
#define _LINUX_BPF_H 1
|
||||
|
||||
#include <uapi/linux/bpf.h>
|
||||
#include <uapi/linux/filter.h>
|
||||
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/file.h>
|
||||
@@ -22,8 +23,10 @@
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/percpu-refcount.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/bpfptr.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/rcupdate_trace.h>
|
||||
|
||||
struct bpf_verifier_env;
|
||||
struct bpf_verifier_log;
|
||||
@@ -398,6 +401,9 @@ enum bpf_type_flag {
|
||||
/* DYNPTR points to a ringbuf record. */
|
||||
DYNPTR_TYPE_RINGBUF = BIT(9 + BPF_BASE_TYPE_BITS),
|
||||
|
||||
/* Size is known at compile time. */
|
||||
MEM_FIXED_SIZE = BIT(10 + BPF_BASE_TYPE_BITS),
|
||||
|
||||
__BPF_TYPE_FLAG_MAX,
|
||||
__BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1,
|
||||
};
|
||||
@@ -461,6 +467,8 @@ enum bpf_arg_type {
|
||||
* all bytes or clear them in error case.
|
||||
*/
|
||||
ARG_PTR_TO_UNINIT_MEM = MEM_UNINIT | ARG_PTR_TO_MEM,
|
||||
/* Pointer to valid memory of size known at compile time. */
|
||||
ARG_PTR_TO_FIXED_SIZE_MEM = MEM_FIXED_SIZE | ARG_PTR_TO_MEM,
|
||||
|
||||
/* This must be the last entry. Its purpose is to ensure the enum is
|
||||
* wide enough to hold the higher bits reserved for bpf_type_flag.
|
||||
@@ -526,6 +534,14 @@ struct bpf_func_proto {
|
||||
u32 *arg5_btf_id;
|
||||
};
|
||||
u32 *arg_btf_id[5];
|
||||
struct {
|
||||
size_t arg1_size;
|
||||
size_t arg2_size;
|
||||
size_t arg3_size;
|
||||
size_t arg4_size;
|
||||
size_t arg5_size;
|
||||
};
|
||||
size_t arg_size[5];
|
||||
};
|
||||
int *ret_btf_id; /* return value btf_id */
|
||||
bool (*allowed)(const struct bpf_prog *prog);
|
||||
@@ -1084,6 +1100,40 @@ struct bpf_prog_aux {
|
||||
};
|
||||
};
|
||||
|
||||
struct bpf_prog {
|
||||
u16 pages; /* Number of allocated pages */
|
||||
u16 jited:1, /* Is our filter JIT'ed? */
|
||||
jit_requested:1,/* archs need to JIT the prog */
|
||||
gpl_compatible:1, /* Is filter GPL compatible? */
|
||||
cb_access:1, /* Is control block accessed? */
|
||||
dst_needed:1, /* Do we need dst entry? */
|
||||
blinding_requested:1, /* needs constant blinding */
|
||||
blinded:1, /* Was blinded */
|
||||
is_func:1, /* program is a bpf function */
|
||||
kprobe_override:1, /* Do we override a kprobe? */
|
||||
has_callchain_buf:1, /* callchain buffer allocated? */
|
||||
enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */
|
||||
call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */
|
||||
call_get_func_ip:1, /* Do we call get_func_ip() */
|
||||
tstamp_type_access:1; /* Accessed __sk_buff->tstamp_type */
|
||||
enum bpf_prog_type type; /* Type of BPF program */
|
||||
enum bpf_attach_type expected_attach_type; /* For some prog types */
|
||||
u32 len; /* Number of filter blocks */
|
||||
u32 jited_len; /* Size of jited insns in bytes */
|
||||
u8 tag[BPF_TAG_SIZE];
|
||||
struct bpf_prog_stats __percpu *stats;
|
||||
int __percpu *active;
|
||||
unsigned int (*bpf_func)(const void *ctx,
|
||||
const struct bpf_insn *insn);
|
||||
struct bpf_prog_aux *aux; /* Auxiliary fields */
|
||||
struct sock_fprog_kern *orig_prog; /* Original BPF program */
|
||||
/* Instructions for interpreter */
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(struct sock_filter, insns);
|
||||
DECLARE_FLEX_ARRAY(struct bpf_insn, insnsi);
|
||||
};
|
||||
};
|
||||
|
||||
struct bpf_array_aux {
|
||||
/* Programs with direct jumps into programs part of this array. */
|
||||
struct list_head poke_progs;
|
||||
@@ -1336,6 +1386,8 @@ extern struct bpf_empty_prog_array bpf_empty_prog_array;
|
||||
|
||||
struct bpf_prog_array *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags);
|
||||
void bpf_prog_array_free(struct bpf_prog_array *progs);
|
||||
/* Use when traversal over the bpf_prog_array uses tasks_trace rcu */
|
||||
void bpf_prog_array_free_sleepable(struct bpf_prog_array *progs);
|
||||
int bpf_prog_array_length(struct bpf_prog_array *progs);
|
||||
bool bpf_prog_array_is_empty(struct bpf_prog_array *array);
|
||||
int bpf_prog_array_copy_to_user(struct bpf_prog_array *progs,
|
||||
@@ -1427,6 +1479,55 @@ bpf_prog_run_array(const struct bpf_prog_array *array,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Notes on RCU design for bpf_prog_arrays containing sleepable programs:
|
||||
*
|
||||
* We use the tasks_trace rcu flavor read section to protect the bpf_prog_array
|
||||
* overall. As a result, we must use the bpf_prog_array_free_sleepable
|
||||
* in order to use the tasks_trace rcu grace period.
|
||||
*
|
||||
* When a non-sleepable program is inside the array, we take the rcu read
|
||||
* section and disable preemption for that program alone, so it can access
|
||||
* rcu-protected dynamically sized maps.
|
||||
*/
|
||||
static __always_inline u32
|
||||
bpf_prog_run_array_sleepable(const struct bpf_prog_array __rcu *array_rcu,
|
||||
const void *ctx, bpf_prog_run_fn run_prog)
|
||||
{
|
||||
const struct bpf_prog_array_item *item;
|
||||
const struct bpf_prog *prog;
|
||||
const struct bpf_prog_array *array;
|
||||
struct bpf_run_ctx *old_run_ctx;
|
||||
struct bpf_trace_run_ctx run_ctx;
|
||||
u32 ret = 1;
|
||||
|
||||
might_fault();
|
||||
|
||||
rcu_read_lock_trace();
|
||||
migrate_disable();
|
||||
|
||||
array = rcu_dereference_check(array_rcu, rcu_read_lock_trace_held());
|
||||
if (unlikely(!array))
|
||||
goto out;
|
||||
old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx);
|
||||
item = &array->items[0];
|
||||
while ((prog = READ_ONCE(item->prog))) {
|
||||
if (!prog->aux->sleepable)
|
||||
rcu_read_lock();
|
||||
|
||||
run_ctx.bpf_cookie = item->bpf_cookie;
|
||||
ret &= run_prog(prog, ctx);
|
||||
item++;
|
||||
|
||||
if (!prog->aux->sleepable)
|
||||
rcu_read_unlock();
|
||||
}
|
||||
bpf_reset_run_ctx(old_run_ctx);
|
||||
out:
|
||||
migrate_enable();
|
||||
rcu_read_unlock_trace();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BPF_SYSCALL
|
||||
DECLARE_PER_CPU(int, bpf_prog_active);
|
||||
extern struct mutex bpf_stats_enabled_mutex;
|
||||
@@ -2104,6 +2205,7 @@ int sock_map_bpf_prog_query(const union bpf_attr *attr,
|
||||
union bpf_attr __user *uattr);
|
||||
|
||||
void sock_map_unhash(struct sock *sk);
|
||||
void sock_map_destroy(struct sock *sk);
|
||||
void sock_map_close(struct sock *sk, long timeout);
|
||||
#else
|
||||
static inline int bpf_prog_offload_init(struct bpf_prog *prog,
|
||||
@@ -2261,12 +2363,9 @@ extern const struct bpf_func_proto bpf_for_each_map_elem_proto;
|
||||
extern const struct bpf_func_proto bpf_btf_find_by_name_kind_proto;
|
||||
extern const struct bpf_func_proto bpf_sk_setsockopt_proto;
|
||||
extern const struct bpf_func_proto bpf_sk_getsockopt_proto;
|
||||
extern const struct bpf_func_proto bpf_kallsyms_lookup_name_proto;
|
||||
extern const struct bpf_func_proto bpf_find_vma_proto;
|
||||
extern const struct bpf_func_proto bpf_loop_proto;
|
||||
extern const struct bpf_func_proto bpf_strncmp_proto;
|
||||
extern const struct bpf_func_proto bpf_copy_from_user_task_proto;
|
||||
extern const struct bpf_func_proto bpf_kptr_xchg_proto;
|
||||
|
||||
const struct bpf_func_proto *tracing_prog_func_proto(
|
||||
enum bpf_func_id func_id, const struct bpf_prog *prog);
|
||||
|
||||
@@ -299,7 +299,7 @@ struct bpf_verifier_state {
|
||||
* If is_state_visited() sees a state with branches > 0 it means
|
||||
* there is a loop. If such state is exactly equal to the current state
|
||||
* it's an infinite loop. Note states_equal() checks for states
|
||||
* equvalency, so two states being 'states_equal' does not mean
|
||||
* equivalency, so two states being 'states_equal' does not mean
|
||||
* infinite loop. The exact comparison is provided by
|
||||
* states_maybe_looping() function. It's a stronger pre-check and
|
||||
* much faster than states_equal().
|
||||
|
||||
@@ -177,6 +177,19 @@ static inline bool btf_type_is_enum(const struct btf_type *t)
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM;
|
||||
}
|
||||
|
||||
static inline bool btf_is_any_enum(const struct btf_type *t)
|
||||
{
|
||||
return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM ||
|
||||
BTF_INFO_KIND(t->info) == BTF_KIND_ENUM64;
|
||||
}
|
||||
|
||||
static inline bool btf_kind_core_compat(const struct btf_type *t1,
|
||||
const struct btf_type *t2)
|
||||
{
|
||||
return BTF_INFO_KIND(t1->info) == BTF_INFO_KIND(t2->info) ||
|
||||
(btf_is_any_enum(t1) && btf_is_any_enum(t2));
|
||||
}
|
||||
|
||||
static inline bool str_is_empty(const char *s)
|
||||
{
|
||||
return !s || !s[0];
|
||||
@@ -192,6 +205,16 @@ static inline bool btf_is_enum(const struct btf_type *t)
|
||||
return btf_kind(t) == BTF_KIND_ENUM;
|
||||
}
|
||||
|
||||
static inline bool btf_is_enum64(const struct btf_type *t)
|
||||
{
|
||||
return btf_kind(t) == BTF_KIND_ENUM64;
|
||||
}
|
||||
|
||||
static inline u64 btf_enum64_value(const struct btf_enum64 *e)
|
||||
{
|
||||
return ((u64)e->val_hi32 << 32) | e->val_lo32;
|
||||
}
|
||||
|
||||
static inline bool btf_is_composite(const struct btf_type *t)
|
||||
{
|
||||
u16 kind = btf_kind(t);
|
||||
@@ -332,6 +355,11 @@ static inline struct btf_enum *btf_enum(const struct btf_type *t)
|
||||
return (struct btf_enum *)(t + 1);
|
||||
}
|
||||
|
||||
static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
|
||||
{
|
||||
return (struct btf_enum64 *)(t + 1);
|
||||
}
|
||||
|
||||
static inline const struct btf_var_secinfo *btf_type_var_secinfo(
|
||||
const struct btf_type *t)
|
||||
{
|
||||
|
||||
@@ -559,40 +559,6 @@ struct bpf_prog_stats {
|
||||
struct u64_stats_sync syncp;
|
||||
} __aligned(2 * sizeof(u64));
|
||||
|
||||
struct bpf_prog {
|
||||
u16 pages; /* Number of allocated pages */
|
||||
u16 jited:1, /* Is our filter JIT'ed? */
|
||||
jit_requested:1,/* archs need to JIT the prog */
|
||||
gpl_compatible:1, /* Is filter GPL compatible? */
|
||||
cb_access:1, /* Is control block accessed? */
|
||||
dst_needed:1, /* Do we need dst entry? */
|
||||
blinding_requested:1, /* needs constant blinding */
|
||||
blinded:1, /* Was blinded */
|
||||
is_func:1, /* program is a bpf function */
|
||||
kprobe_override:1, /* Do we override a kprobe? */
|
||||
has_callchain_buf:1, /* callchain buffer allocated? */
|
||||
enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */
|
||||
call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */
|
||||
call_get_func_ip:1, /* Do we call get_func_ip() */
|
||||
tstamp_type_access:1; /* Accessed __sk_buff->tstamp_type */
|
||||
enum bpf_prog_type type; /* Type of BPF program */
|
||||
enum bpf_attach_type expected_attach_type; /* For some prog types */
|
||||
u32 len; /* Number of filter blocks */
|
||||
u32 jited_len; /* Size of jited insns in bytes */
|
||||
u8 tag[BPF_TAG_SIZE];
|
||||
struct bpf_prog_stats __percpu *stats;
|
||||
int __percpu *active;
|
||||
unsigned int (*bpf_func)(const void *ctx,
|
||||
const struct bpf_insn *insn);
|
||||
struct bpf_prog_aux *aux; /* Auxiliary fields */
|
||||
struct sock_fprog_kern *orig_prog; /* Original BPF program */
|
||||
/* Instructions for interpreter */
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(struct sock_filter, insns);
|
||||
DECLARE_FLEX_ARRAY(struct bpf_insn, insnsi);
|
||||
};
|
||||
};
|
||||
|
||||
struct sk_filter {
|
||||
refcount_t refcnt;
|
||||
struct rcu_head rcu;
|
||||
|
||||
@@ -95,6 +95,7 @@ struct sk_psock {
|
||||
spinlock_t link_lock;
|
||||
refcount_t refcnt;
|
||||
void (*saved_unhash)(struct sock *sk);
|
||||
void (*saved_destroy)(struct sock *sk);
|
||||
void (*saved_close)(struct sock *sk, long timeout);
|
||||
void (*saved_write_space)(struct sock *sk);
|
||||
void (*saved_data_ready)(struct sock *sk);
|
||||
|
||||
@@ -434,6 +434,7 @@ u16 tcp_v4_get_syncookie(struct sock *sk, struct iphdr *iph,
|
||||
struct tcphdr *th, u32 *cookie);
|
||||
u16 tcp_v6_get_syncookie(struct sock *sk, struct ipv6hdr *iph,
|
||||
struct tcphdr *th, u32 *cookie);
|
||||
u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss);
|
||||
u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops,
|
||||
const struct tcp_request_sock_ops *af_ops,
|
||||
struct sock *sk, struct tcphdr *th);
|
||||
|
||||
@@ -3597,10 +3597,11 @@ union bpf_attr {
|
||||
*
|
||||
* *iph* points to the start of the IPv4 or IPv6 header, while
|
||||
* *iph_len* contains **sizeof**\ (**struct iphdr**) or
|
||||
* **sizeof**\ (**struct ip6hdr**).
|
||||
* **sizeof**\ (**struct ipv6hdr**).
|
||||
*
|
||||
* *th* points to the start of the TCP header, while *th_len*
|
||||
* contains **sizeof**\ (**struct tcphdr**).
|
||||
* contains the length of the TCP header (at least
|
||||
* **sizeof**\ (**struct tcphdr**)).
|
||||
* Return
|
||||
* 0 if *iph* and *th* are a valid SYN cookie ACK, or a negative
|
||||
* error otherwise.
|
||||
@@ -3783,10 +3784,11 @@ union bpf_attr {
|
||||
*
|
||||
* *iph* points to the start of the IPv4 or IPv6 header, while
|
||||
* *iph_len* contains **sizeof**\ (**struct iphdr**) or
|
||||
* **sizeof**\ (**struct ip6hdr**).
|
||||
* **sizeof**\ (**struct ipv6hdr**).
|
||||
*
|
||||
* *th* points to the start of the TCP header, while *th_len*
|
||||
* contains the length of the TCP header.
|
||||
* contains the length of the TCP header with options (at least
|
||||
* **sizeof**\ (**struct tcphdr**)).
|
||||
* Return
|
||||
* On success, lower 32 bits hold the generated SYN cookie in
|
||||
* followed by 16 bits which hold the MSS value for that cookie,
|
||||
@@ -5249,6 +5251,80 @@ union bpf_attr {
|
||||
* Pointer to the underlying dynptr data, NULL if the dynptr is
|
||||
* read-only, if the dynptr is invalid, or if the offset and length
|
||||
* is out of bounds.
|
||||
*
|
||||
* s64 bpf_tcp_raw_gen_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th, u32 th_len)
|
||||
* Description
|
||||
* Try to issue a SYN cookie for the packet with corresponding
|
||||
* IPv4/TCP headers, *iph* and *th*, without depending on a
|
||||
* listening socket.
|
||||
*
|
||||
* *iph* points to the IPv4 header.
|
||||
*
|
||||
* *th* points to the start of the TCP header, while *th_len*
|
||||
* contains the length of the TCP header (at least
|
||||
* **sizeof**\ (**struct tcphdr**)).
|
||||
* Return
|
||||
* On success, lower 32 bits hold the generated SYN cookie in
|
||||
* followed by 16 bits which hold the MSS value for that cookie,
|
||||
* and the top 16 bits are unused.
|
||||
*
|
||||
* On failure, the returned value is one of the following:
|
||||
*
|
||||
* **-EINVAL** if *th_len* is invalid.
|
||||
*
|
||||
* s64 bpf_tcp_raw_gen_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th, u32 th_len)
|
||||
* Description
|
||||
* Try to issue a SYN cookie for the packet with corresponding
|
||||
* IPv6/TCP headers, *iph* and *th*, without depending on a
|
||||
* listening socket.
|
||||
*
|
||||
* *iph* points to the IPv6 header.
|
||||
*
|
||||
* *th* points to the start of the TCP header, while *th_len*
|
||||
* contains the length of the TCP header (at least
|
||||
* **sizeof**\ (**struct tcphdr**)).
|
||||
* Return
|
||||
* On success, lower 32 bits hold the generated SYN cookie in
|
||||
* followed by 16 bits which hold the MSS value for that cookie,
|
||||
* and the top 16 bits are unused.
|
||||
*
|
||||
* On failure, the returned value is one of the following:
|
||||
*
|
||||
* **-EINVAL** if *th_len* is invalid.
|
||||
*
|
||||
* **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.
|
||||
*
|
||||
* long bpf_tcp_raw_check_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th)
|
||||
* Description
|
||||
* Check whether *iph* and *th* contain a valid SYN cookie ACK
|
||||
* without depending on a listening socket.
|
||||
*
|
||||
* *iph* points to the IPv4 header.
|
||||
*
|
||||
* *th* points to the TCP header.
|
||||
* Return
|
||||
* 0 if *iph* and *th* are a valid SYN cookie ACK.
|
||||
*
|
||||
* On failure, the returned value is one of the following:
|
||||
*
|
||||
* **-EACCES** if the SYN cookie is not valid.
|
||||
*
|
||||
* long bpf_tcp_raw_check_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th)
|
||||
* Description
|
||||
* Check whether *iph* and *th* contain a valid SYN cookie ACK
|
||||
* without depending on a listening socket.
|
||||
*
|
||||
* *iph* points to the IPv6 header.
|
||||
*
|
||||
* *th* points to the TCP header.
|
||||
* Return
|
||||
* 0 if *iph* and *th* are a valid SYN cookie ACK.
|
||||
*
|
||||
* On failure, the returned value is one of the following:
|
||||
*
|
||||
* **-EACCES** if the SYN cookie is not valid.
|
||||
*
|
||||
* **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
@@ -5455,6 +5531,10 @@ union bpf_attr {
|
||||
FN(dynptr_read), \
|
||||
FN(dynptr_write), \
|
||||
FN(dynptr_data), \
|
||||
FN(tcp_raw_gen_syncookie_ipv4), \
|
||||
FN(tcp_raw_gen_syncookie_ipv6), \
|
||||
FN(tcp_raw_check_syncookie_ipv4), \
|
||||
FN(tcp_raw_check_syncookie_ipv6), \
|
||||
/* */
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
|
||||
@@ -36,10 +36,10 @@ struct btf_type {
|
||||
* bits 24-28: kind (e.g. int, ptr, array...etc)
|
||||
* bits 29-30: unused
|
||||
* bit 31: kind_flag, currently used by
|
||||
* struct, union and fwd
|
||||
* struct, union, enum, fwd and enum64
|
||||
*/
|
||||
__u32 info;
|
||||
/* "size" is used by INT, ENUM, STRUCT, UNION and DATASEC.
|
||||
/* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
|
||||
* "size" tells the size of the type it is describing.
|
||||
*
|
||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
||||
@@ -63,7 +63,7 @@ enum {
|
||||
BTF_KIND_ARRAY = 3, /* Array */
|
||||
BTF_KIND_STRUCT = 4, /* Struct */
|
||||
BTF_KIND_UNION = 5, /* Union */
|
||||
BTF_KIND_ENUM = 6, /* Enumeration */
|
||||
BTF_KIND_ENUM = 6, /* Enumeration up to 32-bit values */
|
||||
BTF_KIND_FWD = 7, /* Forward */
|
||||
BTF_KIND_TYPEDEF = 8, /* Typedef */
|
||||
BTF_KIND_VOLATILE = 9, /* Volatile */
|
||||
@@ -76,6 +76,7 @@ enum {
|
||||
BTF_KIND_FLOAT = 16, /* Floating point */
|
||||
BTF_KIND_DECL_TAG = 17, /* Decl Tag */
|
||||
BTF_KIND_TYPE_TAG = 18, /* Type Tag */
|
||||
BTF_KIND_ENUM64 = 19, /* Enumeration up to 64-bit values */
|
||||
|
||||
NR_BTF_KINDS,
|
||||
BTF_KIND_MAX = NR_BTF_KINDS - 1,
|
||||
@@ -186,4 +187,14 @@ struct btf_decl_tag {
|
||||
__s32 component_idx;
|
||||
};
|
||||
|
||||
/* BTF_KIND_ENUM64 is followed by multiple "struct btf_enum64".
|
||||
* The exact number of btf_enum64 is stored in the vlen (of the
|
||||
* info in "struct btf_type").
|
||||
*/
|
||||
struct btf_enum64 {
|
||||
__u32 name_off;
|
||||
__u32 val_lo32;
|
||||
__u32 val_hi32;
|
||||
};
|
||||
|
||||
#endif /* _UAPI__LINUX_BTF_H__ */
|
||||
+128
-14
@@ -309,6 +309,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = {
|
||||
[BTF_KIND_FLOAT] = "FLOAT",
|
||||
[BTF_KIND_DECL_TAG] = "DECL_TAG",
|
||||
[BTF_KIND_TYPE_TAG] = "TYPE_TAG",
|
||||
[BTF_KIND_ENUM64] = "ENUM64",
|
||||
};
|
||||
|
||||
const char *btf_type_str(const struct btf_type *t)
|
||||
@@ -666,6 +667,7 @@ static bool btf_type_has_size(const struct btf_type *t)
|
||||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_DATASEC:
|
||||
case BTF_KIND_FLOAT:
|
||||
case BTF_KIND_ENUM64:
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -711,6 +713,11 @@ static const struct btf_decl_tag *btf_type_decl_tag(const struct btf_type *t)
|
||||
return (const struct btf_decl_tag *)(t + 1);
|
||||
}
|
||||
|
||||
static const struct btf_enum64 *btf_type_enum64(const struct btf_type *t)
|
||||
{
|
||||
return (const struct btf_enum64 *)(t + 1);
|
||||
}
|
||||
|
||||
static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t)
|
||||
{
|
||||
return kind_ops[BTF_INFO_KIND(t->info)];
|
||||
@@ -1019,6 +1026,7 @@ static const char *btf_show_name(struct btf_show *show)
|
||||
parens = "{";
|
||||
break;
|
||||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_ENUM64:
|
||||
prefix = "enum";
|
||||
break;
|
||||
default:
|
||||
@@ -1834,6 +1842,7 @@ __btf_resolve_size(const struct btf *btf, const struct btf_type *type,
|
||||
case BTF_KIND_UNION:
|
||||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_FLOAT:
|
||||
case BTF_KIND_ENUM64:
|
||||
size = type->size;
|
||||
goto resolved;
|
||||
|
||||
@@ -3670,6 +3679,7 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
|
||||
{
|
||||
const struct btf_enum *enums = btf_type_enum(t);
|
||||
struct btf *btf = env->btf;
|
||||
const char *fmt_str;
|
||||
u16 i, nr_enums;
|
||||
u32 meta_needed;
|
||||
|
||||
@@ -3683,11 +3693,6 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t)) {
|
||||
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (t->size > 8 || !is_power_of_2(t->size)) {
|
||||
btf_verifier_log_type(env, t, "Unexpected size");
|
||||
return -EINVAL;
|
||||
@@ -3718,7 +3723,8 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
|
||||
|
||||
if (env->log.level == BPF_LOG_KERNEL)
|
||||
continue;
|
||||
btf_verifier_log(env, "\t%s val=%d\n",
|
||||
fmt_str = btf_type_kflag(t) ? "\t%s val=%d\n" : "\t%s val=%u\n";
|
||||
btf_verifier_log(env, fmt_str,
|
||||
__btf_name_by_offset(btf, enums[i].name_off),
|
||||
enums[i].val);
|
||||
}
|
||||
@@ -3759,7 +3765,10 @@ static void btf_enum_show(const struct btf *btf, const struct btf_type *t,
|
||||
return;
|
||||
}
|
||||
|
||||
btf_show_type_value(show, "%d", v);
|
||||
if (btf_type_kflag(t))
|
||||
btf_show_type_value(show, "%d", v);
|
||||
else
|
||||
btf_show_type_value(show, "%u", v);
|
||||
btf_show_end_type(show);
|
||||
}
|
||||
|
||||
@@ -3772,6 +3781,109 @@ static struct btf_kind_operations enum_ops = {
|
||||
.show = btf_enum_show,
|
||||
};
|
||||
|
||||
static s32 btf_enum64_check_meta(struct btf_verifier_env *env,
|
||||
const struct btf_type *t,
|
||||
u32 meta_left)
|
||||
{
|
||||
const struct btf_enum64 *enums = btf_type_enum64(t);
|
||||
struct btf *btf = env->btf;
|
||||
const char *fmt_str;
|
||||
u16 i, nr_enums;
|
||||
u32 meta_needed;
|
||||
|
||||
nr_enums = btf_type_vlen(t);
|
||||
meta_needed = nr_enums * sizeof(*enums);
|
||||
|
||||
if (meta_left < meta_needed) {
|
||||
btf_verifier_log_basic(env, t,
|
||||
"meta_left:%u meta_needed:%u",
|
||||
meta_left, meta_needed);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (t->size > 8 || !is_power_of_2(t->size)) {
|
||||
btf_verifier_log_type(env, t, "Unexpected size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* enum type either no name or a valid one */
|
||||
if (t->name_off &&
|
||||
!btf_name_valid_identifier(env->btf, t->name_off)) {
|
||||
btf_verifier_log_type(env, t, "Invalid name");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
btf_verifier_log_type(env, t, NULL);
|
||||
|
||||
for (i = 0; i < nr_enums; i++) {
|
||||
if (!btf_name_offset_valid(btf, enums[i].name_off)) {
|
||||
btf_verifier_log(env, "\tInvalid name_offset:%u",
|
||||
enums[i].name_off);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* enum member must have a valid name */
|
||||
if (!enums[i].name_off ||
|
||||
!btf_name_valid_identifier(btf, enums[i].name_off)) {
|
||||
btf_verifier_log_type(env, t, "Invalid name");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (env->log.level == BPF_LOG_KERNEL)
|
||||
continue;
|
||||
|
||||
fmt_str = btf_type_kflag(t) ? "\t%s val=%lld\n" : "\t%s val=%llu\n";
|
||||
btf_verifier_log(env, fmt_str,
|
||||
__btf_name_by_offset(btf, enums[i].name_off),
|
||||
btf_enum64_value(enums + i));
|
||||
}
|
||||
|
||||
return meta_needed;
|
||||
}
|
||||
|
||||
static void btf_enum64_show(const struct btf *btf, const struct btf_type *t,
|
||||
u32 type_id, void *data, u8 bits_offset,
|
||||
struct btf_show *show)
|
||||
{
|
||||
const struct btf_enum64 *enums = btf_type_enum64(t);
|
||||
u32 i, nr_enums = btf_type_vlen(t);
|
||||
void *safe_data;
|
||||
s64 v;
|
||||
|
||||
safe_data = btf_show_start_type(show, t, type_id, data);
|
||||
if (!safe_data)
|
||||
return;
|
||||
|
||||
v = *(u64 *)safe_data;
|
||||
|
||||
for (i = 0; i < nr_enums; i++) {
|
||||
if (v != btf_enum64_value(enums + i))
|
||||
continue;
|
||||
|
||||
btf_show_type_value(show, "%s",
|
||||
__btf_name_by_offset(btf,
|
||||
enums[i].name_off));
|
||||
|
||||
btf_show_end_type(show);
|
||||
return;
|
||||
}
|
||||
|
||||
if (btf_type_kflag(t))
|
||||
btf_show_type_value(show, "%lld", v);
|
||||
else
|
||||
btf_show_type_value(show, "%llu", v);
|
||||
btf_show_end_type(show);
|
||||
}
|
||||
|
||||
static struct btf_kind_operations enum64_ops = {
|
||||
.check_meta = btf_enum64_check_meta,
|
||||
.resolve = btf_df_resolve,
|
||||
.check_member = btf_enum_check_member,
|
||||
.check_kflag_member = btf_enum_check_kflag_member,
|
||||
.log_details = btf_enum_log,
|
||||
.show = btf_enum64_show,
|
||||
};
|
||||
|
||||
static s32 btf_func_proto_check_meta(struct btf_verifier_env *env,
|
||||
const struct btf_type *t,
|
||||
u32 meta_left)
|
||||
@@ -4438,6 +4550,7 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = {
|
||||
[BTF_KIND_FLOAT] = &float_ops,
|
||||
[BTF_KIND_DECL_TAG] = &decl_tag_ops,
|
||||
[BTF_KIND_TYPE_TAG] = &modifier_ops,
|
||||
[BTF_KIND_ENUM64] = &enum64_ops,
|
||||
};
|
||||
|
||||
static s32 btf_check_meta(struct btf_verifier_env *env,
|
||||
@@ -5299,7 +5412,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
|
||||
/* skip modifiers */
|
||||
while (btf_type_is_modifier(t))
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
if (btf_type_is_small_int(t) || btf_type_is_enum(t))
|
||||
if (btf_type_is_small_int(t) || btf_is_any_enum(t))
|
||||
/* accessing a scalar */
|
||||
return true;
|
||||
if (!btf_type_is_ptr(t)) {
|
||||
@@ -5763,7 +5876,7 @@ static int __get_type_size(struct btf *btf, u32 btf_id,
|
||||
if (btf_type_is_ptr(t))
|
||||
/* kernel size of pointer. Not BPF's size of pointer*/
|
||||
return sizeof(void *);
|
||||
if (btf_type_is_int(t) || btf_type_is_enum(t))
|
||||
if (btf_type_is_int(t) || btf_is_any_enum(t))
|
||||
return t->size;
|
||||
*bad_type = t;
|
||||
return -EINVAL;
|
||||
@@ -5911,7 +6024,7 @@ static int btf_check_func_type_match(struct bpf_verifier_log *log,
|
||||
* to context only. And only global functions can be replaced.
|
||||
* Hence type check only those types.
|
||||
*/
|
||||
if (btf_type_is_int(t1) || btf_type_is_enum(t1))
|
||||
if (btf_type_is_int(t1) || btf_is_any_enum(t1))
|
||||
continue;
|
||||
if (!btf_type_is_ptr(t1)) {
|
||||
bpf_log(log,
|
||||
@@ -6409,7 +6522,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
while (btf_type_is_modifier(t))
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
if (!btf_type_is_int(t) && !btf_type_is_enum(t)) {
|
||||
if (!btf_type_is_int(t) && !btf_is_any_enum(t)) {
|
||||
bpf_log(log,
|
||||
"Global function %s() doesn't return scalar. Only those are supported.\n",
|
||||
tname);
|
||||
@@ -6424,7 +6537,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
|
||||
t = btf_type_by_id(btf, args[i].type);
|
||||
while (btf_type_is_modifier(t))
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
if (btf_type_is_int(t) || btf_type_is_enum(t)) {
|
||||
if (btf_type_is_int(t) || btf_is_any_enum(t)) {
|
||||
reg->type = SCALAR_VALUE;
|
||||
continue;
|
||||
}
|
||||
@@ -7336,6 +7449,7 @@ recur:
|
||||
case BTF_KIND_UNION:
|
||||
case BTF_KIND_ENUM:
|
||||
case BTF_KIND_FWD:
|
||||
case BTF_KIND_ENUM64:
|
||||
return 1;
|
||||
case BTF_KIND_INT:
|
||||
/* just reject deprecated bitfield-like integers; all other
|
||||
@@ -7388,10 +7502,10 @@ recur:
|
||||
* field-based relocations. This function assumes that root types were already
|
||||
* checked for name match. Beyond that initial root-level name check, names
|
||||
* are completely ignored. Compatibility rules are as follows:
|
||||
* - any two STRUCTs/UNIONs/FWDs/ENUMs/INTs are considered compatible, but
|
||||
* - any two STRUCTs/UNIONs/FWDs/ENUMs/INTs/ENUM64s are considered compatible, but
|
||||
* kind should match for local and target types (i.e., STRUCT is not
|
||||
* compatible with UNION);
|
||||
* - for ENUMs, the size is ignored;
|
||||
* - for ENUMs/ENUM64s, the size is ignored;
|
||||
* - for INT, size and signedness are ignored;
|
||||
* - for ARRAY, dimensionality is ignored, element types are checked for
|
||||
* compatibility recursively;
|
||||
|
||||
+60
-10
@@ -720,6 +720,60 @@ static struct bpf_prog_list *find_detach_entry(struct list_head *progs,
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* purge_effective_progs() - After compute_effective_progs fails to alloc new
|
||||
* cgrp->bpf.inactive table we can recover by
|
||||
* recomputing the array in place.
|
||||
*
|
||||
* @cgrp: The cgroup which descendants to travers
|
||||
* @prog: A program to detach or NULL
|
||||
* @link: A link to detach or NULL
|
||||
* @atype: Type of detach operation
|
||||
*/
|
||||
static void purge_effective_progs(struct cgroup *cgrp, struct bpf_prog *prog,
|
||||
struct bpf_cgroup_link *link,
|
||||
enum cgroup_bpf_attach_type atype)
|
||||
{
|
||||
struct cgroup_subsys_state *css;
|
||||
struct bpf_prog_array *progs;
|
||||
struct bpf_prog_list *pl;
|
||||
struct list_head *head;
|
||||
struct cgroup *cg;
|
||||
int pos;
|
||||
|
||||
/* recompute effective prog array in place */
|
||||
css_for_each_descendant_pre(css, &cgrp->self) {
|
||||
struct cgroup *desc = container_of(css, struct cgroup, self);
|
||||
|
||||
if (percpu_ref_is_zero(&desc->bpf.refcnt))
|
||||
continue;
|
||||
|
||||
/* find position of link or prog in effective progs array */
|
||||
for (pos = 0, cg = desc; cg; cg = cgroup_parent(cg)) {
|
||||
if (pos && !(cg->bpf.flags[atype] & BPF_F_ALLOW_MULTI))
|
||||
continue;
|
||||
|
||||
head = &cg->bpf.progs[atype];
|
||||
list_for_each_entry(pl, head, node) {
|
||||
if (!prog_list_prog(pl))
|
||||
continue;
|
||||
if (pl->prog == prog && pl->link == link)
|
||||
goto found;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
found:
|
||||
BUG_ON(!cg);
|
||||
progs = rcu_dereference_protected(
|
||||
desc->bpf.effective[atype],
|
||||
lockdep_is_held(&cgroup_mutex));
|
||||
|
||||
/* Remove the program from the array */
|
||||
WARN_ONCE(bpf_prog_array_delete_safe_at(progs, pos),
|
||||
"Failed to purge a prog from array at index %d", pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* __cgroup_bpf_detach() - Detach the program or link from a cgroup, and
|
||||
* propagate the change to descendants
|
||||
@@ -739,7 +793,6 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
|
||||
struct bpf_prog_list *pl;
|
||||
struct list_head *progs;
|
||||
u32 flags;
|
||||
int err;
|
||||
|
||||
atype = to_cgroup_bpf_attach_type(type);
|
||||
if (atype < 0)
|
||||
@@ -761,9 +814,12 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
|
||||
pl->prog = NULL;
|
||||
pl->link = NULL;
|
||||
|
||||
err = update_effective_progs(cgrp, atype);
|
||||
if (err)
|
||||
goto cleanup;
|
||||
if (update_effective_progs(cgrp, atype)) {
|
||||
/* if update effective array failed replace the prog with a dummy prog*/
|
||||
pl->prog = old_prog;
|
||||
pl->link = link;
|
||||
purge_effective_progs(cgrp, old_prog, link, atype);
|
||||
}
|
||||
|
||||
/* now can actually delete it from this cgroup list */
|
||||
list_del(&pl->node);
|
||||
@@ -775,12 +831,6 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
|
||||
bpf_prog_put(old_prog);
|
||||
static_branch_dec(&cgroup_bpf_enabled_key[atype]);
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
/* restore back prog or link */
|
||||
pl->prog = old_prog;
|
||||
pl->link = link;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
|
||||
|
||||
+16
-1
@@ -176,7 +176,7 @@ void bpf_prog_jit_attempt_done(struct bpf_prog *prog)
|
||||
* here is relative to the prog itself instead of the main prog.
|
||||
* This array has one entry for each xlated bpf insn.
|
||||
*
|
||||
* jited_off is the byte off to the last byte of the jited insn.
|
||||
* jited_off is the byte off to the end of the jited insn.
|
||||
*
|
||||
* Hence, with
|
||||
* insn_start:
|
||||
@@ -2279,6 +2279,21 @@ void bpf_prog_array_free(struct bpf_prog_array *progs)
|
||||
kfree_rcu(progs, rcu);
|
||||
}
|
||||
|
||||
static void __bpf_prog_array_free_sleepable_cb(struct rcu_head *rcu)
|
||||
{
|
||||
struct bpf_prog_array *progs;
|
||||
|
||||
progs = container_of(rcu, struct bpf_prog_array, rcu);
|
||||
kfree_rcu(progs, rcu);
|
||||
}
|
||||
|
||||
void bpf_prog_array_free_sleepable(struct bpf_prog_array *progs)
|
||||
{
|
||||
if (!progs || progs == &bpf_empty_prog_array.hdr)
|
||||
return;
|
||||
call_rcu_tasks_trace(&progs->rcu, __bpf_prog_array_free_sleepable_cb);
|
||||
}
|
||||
|
||||
int bpf_prog_array_length(struct bpf_prog_array *array)
|
||||
{
|
||||
struct bpf_prog_array_item *item;
|
||||
|
||||
@@ -584,7 +584,7 @@ BPF_CALL_3(bpf_strncmp, const char *, s1, u32, s1_sz, const char *, s2)
|
||||
return strncmp(s1, s2, s1_sz);
|
||||
}
|
||||
|
||||
const struct bpf_func_proto bpf_strncmp_proto = {
|
||||
static const struct bpf_func_proto bpf_strncmp_proto = {
|
||||
.func = bpf_strncmp,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_INTEGER,
|
||||
@@ -1402,7 +1402,7 @@ BPF_CALL_2(bpf_kptr_xchg, void *, map_value, void *, ptr)
|
||||
*/
|
||||
#define BPF_PTR_POISON ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA))
|
||||
|
||||
const struct bpf_func_proto bpf_kptr_xchg_proto = {
|
||||
static const struct bpf_func_proto bpf_kptr_xchg_proto = {
|
||||
.func = bpf_kptr_xchg,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_PTR_TO_BTF_ID_OR_NULL,
|
||||
@@ -1487,7 +1487,7 @@ error:
|
||||
return err;
|
||||
}
|
||||
|
||||
const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
|
||||
static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
|
||||
.func = bpf_dynptr_from_mem,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_INTEGER,
|
||||
@@ -1513,7 +1513,7 @@ BPF_CALL_4(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bpf_func_proto bpf_dynptr_read_proto = {
|
||||
static const struct bpf_func_proto bpf_dynptr_read_proto = {
|
||||
.func = bpf_dynptr_read,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_INTEGER,
|
||||
@@ -1539,7 +1539,7 @@ BPF_CALL_4(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bpf_func_proto bpf_dynptr_write_proto = {
|
||||
static const struct bpf_func_proto bpf_dynptr_write_proto = {
|
||||
.func = bpf_dynptr_write,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_INTEGER,
|
||||
@@ -1566,7 +1566,7 @@ BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len
|
||||
return (unsigned long)(ptr->data + ptr->offset + offset);
|
||||
}
|
||||
|
||||
const struct bpf_func_proto bpf_dynptr_data_proto = {
|
||||
static const struct bpf_func_proto bpf_dynptr_data_proto = {
|
||||
.func = bpf_dynptr_data,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_PTR_TO_DYNPTR_MEM_OR_NULL,
|
||||
|
||||
@@ -31,7 +31,7 @@ static inline void pcpu_freelist_push_node(struct pcpu_freelist_head *head,
|
||||
struct pcpu_freelist_node *node)
|
||||
{
|
||||
node->next = head->first;
|
||||
head->first = node;
|
||||
WRITE_ONCE(head->first, node);
|
||||
}
|
||||
|
||||
static inline void ___pcpu_freelist_push(struct pcpu_freelist_head *head,
|
||||
@@ -130,14 +130,17 @@ static struct pcpu_freelist_node *___pcpu_freelist_pop(struct pcpu_freelist *s)
|
||||
orig_cpu = cpu = raw_smp_processor_id();
|
||||
while (1) {
|
||||
head = per_cpu_ptr(s->freelist, cpu);
|
||||
if (!READ_ONCE(head->first))
|
||||
goto next_cpu;
|
||||
raw_spin_lock(&head->lock);
|
||||
node = head->first;
|
||||
if (node) {
|
||||
head->first = node->next;
|
||||
WRITE_ONCE(head->first, node->next);
|
||||
raw_spin_unlock(&head->lock);
|
||||
return node;
|
||||
}
|
||||
raw_spin_unlock(&head->lock);
|
||||
next_cpu:
|
||||
cpu = cpumask_next(cpu, cpu_possible_mask);
|
||||
if (cpu >= nr_cpu_ids)
|
||||
cpu = 0;
|
||||
@@ -146,10 +149,12 @@ static struct pcpu_freelist_node *___pcpu_freelist_pop(struct pcpu_freelist *s)
|
||||
}
|
||||
|
||||
/* per cpu lists are all empty, try extralist */
|
||||
if (!READ_ONCE(s->extralist.first))
|
||||
return NULL;
|
||||
raw_spin_lock(&s->extralist.lock);
|
||||
node = s->extralist.first;
|
||||
if (node)
|
||||
s->extralist.first = node->next;
|
||||
WRITE_ONCE(s->extralist.first, node->next);
|
||||
raw_spin_unlock(&s->extralist.lock);
|
||||
return node;
|
||||
}
|
||||
@@ -164,15 +169,18 @@ ___pcpu_freelist_pop_nmi(struct pcpu_freelist *s)
|
||||
orig_cpu = cpu = raw_smp_processor_id();
|
||||
while (1) {
|
||||
head = per_cpu_ptr(s->freelist, cpu);
|
||||
if (!READ_ONCE(head->first))
|
||||
goto next_cpu;
|
||||
if (raw_spin_trylock(&head->lock)) {
|
||||
node = head->first;
|
||||
if (node) {
|
||||
head->first = node->next;
|
||||
WRITE_ONCE(head->first, node->next);
|
||||
raw_spin_unlock(&head->lock);
|
||||
return node;
|
||||
}
|
||||
raw_spin_unlock(&head->lock);
|
||||
}
|
||||
next_cpu:
|
||||
cpu = cpumask_next(cpu, cpu_possible_mask);
|
||||
if (cpu >= nr_cpu_ids)
|
||||
cpu = 0;
|
||||
@@ -181,11 +189,11 @@ ___pcpu_freelist_pop_nmi(struct pcpu_freelist *s)
|
||||
}
|
||||
|
||||
/* cannot pop from per cpu lists, try extralist */
|
||||
if (!raw_spin_trylock(&s->extralist.lock))
|
||||
if (!READ_ONCE(s->extralist.first) || !raw_spin_trylock(&s->extralist.lock))
|
||||
return NULL;
|
||||
node = s->extralist.first;
|
||||
if (node)
|
||||
s->extralist.first = node->next;
|
||||
WRITE_ONCE(s->extralist.first, node->next);
|
||||
raw_spin_unlock(&s->extralist.lock);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -4090,14 +4090,15 @@ static int bpf_prog_get_info_by_fd(struct file *file,
|
||||
info.nr_jited_line_info = 0;
|
||||
if (info.nr_jited_line_info && ulen) {
|
||||
if (bpf_dump_raw_ok(file->f_cred)) {
|
||||
unsigned long line_addr;
|
||||
__u64 __user *user_linfo;
|
||||
u32 i;
|
||||
|
||||
user_linfo = u64_to_user_ptr(info.jited_line_info);
|
||||
ulen = min_t(u32, info.nr_jited_line_info, ulen);
|
||||
for (i = 0; i < ulen; i++) {
|
||||
if (put_user((__u64)(long)prog->aux->jited_linfo[i],
|
||||
&user_linfo[i]))
|
||||
line_addr = (unsigned long)prog->aux->jited_linfo[i];
|
||||
if (put_user((__u64)line_addr, &user_linfo[i]))
|
||||
return -EFAULT;
|
||||
}
|
||||
} else {
|
||||
@@ -5130,7 +5131,7 @@ BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flag
|
||||
return *res ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
|
||||
static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
|
||||
.func = bpf_kallsyms_lookup_name,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_INTEGER,
|
||||
|
||||
+35
-14
@@ -5848,6 +5848,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
|
||||
struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno];
|
||||
enum bpf_arg_type arg_type = fn->arg_type[arg];
|
||||
enum bpf_reg_type type = reg->type;
|
||||
u32 *arg_btf_id = NULL;
|
||||
int err = 0;
|
||||
|
||||
if (arg_type == ARG_DONTCARE)
|
||||
@@ -5884,7 +5885,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
|
||||
*/
|
||||
goto skip_type_check;
|
||||
|
||||
err = check_reg_type(env, regno, arg_type, fn->arg_btf_id[arg], meta);
|
||||
/* arg_btf_id and arg_size are in a union. */
|
||||
if (base_type(arg_type) == ARG_PTR_TO_BTF_ID)
|
||||
arg_btf_id = fn->arg_btf_id[arg];
|
||||
|
||||
err = check_reg_type(env, regno, arg_type, arg_btf_id, meta);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -6011,6 +6016,11 @@ skip_type_check:
|
||||
* next is_mem_size argument below.
|
||||
*/
|
||||
meta->raw_mode = arg_type & MEM_UNINIT;
|
||||
if (arg_type & MEM_FIXED_SIZE) {
|
||||
err = check_helper_mem_access(env, regno,
|
||||
fn->arg_size[arg], false,
|
||||
meta);
|
||||
}
|
||||
} else if (arg_type_is_mem_size(arg_type)) {
|
||||
bool zero_size_allowed = (arg_type == ARG_CONST_SIZE_OR_ZERO);
|
||||
|
||||
@@ -6400,11 +6410,19 @@ static bool check_raw_mode_ok(const struct bpf_func_proto *fn)
|
||||
return count <= 1;
|
||||
}
|
||||
|
||||
static bool check_args_pair_invalid(enum bpf_arg_type arg_curr,
|
||||
enum bpf_arg_type arg_next)
|
||||
static bool check_args_pair_invalid(const struct bpf_func_proto *fn, int arg)
|
||||
{
|
||||
return (base_type(arg_curr) == ARG_PTR_TO_MEM) !=
|
||||
arg_type_is_mem_size(arg_next);
|
||||
bool is_fixed = fn->arg_type[arg] & MEM_FIXED_SIZE;
|
||||
bool has_size = fn->arg_size[arg] != 0;
|
||||
bool is_next_size = false;
|
||||
|
||||
if (arg + 1 < ARRAY_SIZE(fn->arg_type))
|
||||
is_next_size = arg_type_is_mem_size(fn->arg_type[arg + 1]);
|
||||
|
||||
if (base_type(fn->arg_type[arg]) != ARG_PTR_TO_MEM)
|
||||
return is_next_size;
|
||||
|
||||
return has_size == is_next_size || is_next_size == is_fixed;
|
||||
}
|
||||
|
||||
static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
|
||||
@@ -6415,11 +6433,11 @@ static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
|
||||
* helper function specification.
|
||||
*/
|
||||
if (arg_type_is_mem_size(fn->arg1_type) ||
|
||||
base_type(fn->arg5_type) == ARG_PTR_TO_MEM ||
|
||||
check_args_pair_invalid(fn->arg1_type, fn->arg2_type) ||
|
||||
check_args_pair_invalid(fn->arg2_type, fn->arg3_type) ||
|
||||
check_args_pair_invalid(fn->arg3_type, fn->arg4_type) ||
|
||||
check_args_pair_invalid(fn->arg4_type, fn->arg5_type))
|
||||
check_args_pair_invalid(fn, 0) ||
|
||||
check_args_pair_invalid(fn, 1) ||
|
||||
check_args_pair_invalid(fn, 2) ||
|
||||
check_args_pair_invalid(fn, 3) ||
|
||||
check_args_pair_invalid(fn, 4))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -6460,7 +6478,10 @@ static bool check_btf_id_ok(const struct bpf_func_proto *fn)
|
||||
if (base_type(fn->arg_type[i]) == ARG_PTR_TO_BTF_ID && !fn->arg_btf_id[i])
|
||||
return false;
|
||||
|
||||
if (base_type(fn->arg_type[i]) != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i])
|
||||
if (base_type(fn->arg_type[i]) != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i] &&
|
||||
/* arg_btf_id and arg_size are in a union. */
|
||||
(base_type(fn->arg_type[i]) != ARG_PTR_TO_MEM ||
|
||||
!(fn->arg_type[i] & MEM_FIXED_SIZE)))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -10901,7 +10922,7 @@ static int check_btf_func(struct bpf_verifier_env *env,
|
||||
goto err_free;
|
||||
ret_type = btf_type_skip_modifiers(btf, func_proto->type, NULL);
|
||||
scalar_return =
|
||||
btf_type_is_small_int(ret_type) || btf_type_is_enum(ret_type);
|
||||
btf_type_is_small_int(ret_type) || btf_is_any_enum(ret_type);
|
||||
if (i && !scalar_return && env->subprog_info[i].has_ld_abs) {
|
||||
verbose(env, "LD_ABS is only allowed in functions that return 'int'.\n");
|
||||
goto err_free;
|
||||
@@ -14829,8 +14850,8 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
|
||||
}
|
||||
|
||||
if (prog->aux->sleepable && prog->type != BPF_PROG_TYPE_TRACING &&
|
||||
prog->type != BPF_PROG_TYPE_LSM) {
|
||||
verbose(env, "Only fentry/fexit/fmod_ret and lsm programs can be sleepable\n");
|
||||
prog->type != BPF_PROG_TYPE_LSM && prog->type != BPF_PROG_TYPE_KPROBE) {
|
||||
verbose(env, "Only fentry/fexit/fmod_ret, lsm, and kprobe/uprobe programs can be sleepable\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
Loaded 20 of 92 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user