Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next

Daniel Borkmann says:

====================
pull-request: bpf-next 2018-12-21

The following pull-request contains BPF updates for your *net-next* tree.

There is a merge conflict in test_verifier.c. Result looks as follows:

        [...]
        },
        {
                "calls: cross frame pruning",
                .insns = {
                [...]
                .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
                .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
                .result_unpriv = REJECT,
                .errstr = "!read_ok",
                .result = REJECT,
	},
        {
                "jset: functional",
                .insns = {
        [...]
        {
                "jset: unknown const compare not taken",
                .insns = {
                        BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
                                     BPF_FUNC_get_prandom_u32),
                        BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 1),
                        BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
                        BPF_EXIT_INSN(),
                },
                .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
                .errstr_unpriv = "!read_ok",
                .result_unpriv = REJECT,
                .errstr = "!read_ok",
                .result = REJECT,
        },
        [...]
        {
                "jset: range",
                .insns = {
                [...]
                },
                .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
                .result_unpriv = ACCEPT,
                .result = ACCEPT,
        },

The main changes are:

1) Various BTF related improvements in order to get line info
   working. Meaning, verifier will now annotate the corresponding
   BPF C code to the error log, from Martin and Yonghong.

2) Implement support for raw BPF tracepoints in modules, from Matt.

3) Add several improvements to verifier state logic, namely speeding
   up stacksafe check, optimizations for stack state equivalence
   test and safety checks for liveness analysis, from Alexei.

4) Teach verifier to make use of BPF_JSET instruction, add several
   test cases to kselftests and remove nfp specific JSET optimization
   now that verifier has awareness, from Jakub.

5) Improve BPF verifier's slot_type marking logic in order to
   allow more stack slot sharing, from Jiong.

6) Add sk_msg->size member for context access and add set of fixes
   and improvements to make sock_map with kTLS usable with openssl
   based applications, from John.

7) Several cleanups and documentation updates in bpftool as well as
   auto-mount of tracefs for "bpftool prog tracelog" command,
   from Quentin.

8) Include sub-program tags from now on in bpf_prog_info in order to
   have a reliable way for user space to get all tags of the program
   e.g. needed for kallsyms correlation, from Song.

9) Add BTF annotations for cgroup_local_storage BPF maps and
   implement bpf fs pretty print support, from Roman.

10) Fix bpftool in order to allow for cross-compilation, from Ivan.

11) Update of bpftool license to GPLv2-only + BSD-2-Clause in order
    to be compatible with libbfd and allow for Debian packaging,
    from Jakub.

12) Remove an obsolete prog->aux sanitation in dump and get rid of
    version check for prog load, from Daniel.

13) Fix a memory leak in libbpf's line info handling, from Prashant.

14) Fix cpumap's frame alignment for build_skb() so that skb_shared_info
    does not get unaligned, from Jesper.

15) Fix test_progs kselftest to work with older compilers which are less
    smart in optimizing (and thus throwing build error), from Stanislav.

16) Cleanup and simplify AF_XDP socket teardown, from Björn.

17) Fix sk lookup in BPF kselftest's test_sock_addr with regards
    to netns_id argument, from Andrey.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2018-12-20 17:31:36 -08:00
Родитель e770454fab 1cf4a0ccc5
Коммит 339bbff2d6
64 изменённых файлов: 2334 добавлений и 683 удалений

Просмотреть файл

@ -932,6 +932,7 @@ skip_init_ctx:
prog->jited_len = image_size; prog->jited_len = image_size;
if (!prog->is_func || extra_pass) { if (!prog->is_func || extra_pass) {
bpf_prog_fill_jited_linfo(prog, ctx.offset);
out_off: out_off:
kfree(ctx.offset); kfree(ctx.offset);
kfree(jit_data); kfree(jit_data);

Просмотреть файл

@ -1575,6 +1575,7 @@ skip_init_ctx:
prog->jited_len = image_size; prog->jited_len = image_size;
if (!prog->is_func || extra_pass) { if (!prog->is_func || extra_pass) {
bpf_prog_fill_jited_linfo(prog, ctx.offset);
out_off: out_off:
kfree(ctx.offset); kfree(ctx.offset);
kfree(jit_data); kfree(jit_data);

Просмотреть файл

@ -3052,26 +3052,19 @@ static int jset_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
{ {
const struct bpf_insn *insn = &meta->insn; const struct bpf_insn *insn = &meta->insn;
u64 imm = insn->imm; /* sign extend */ u64 imm = insn->imm; /* sign extend */
u8 dst_gpr = insn->dst_reg * 2;
swreg tmp_reg; swreg tmp_reg;
if (!imm) { tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog));
meta->skip = true; emit_alu(nfp_prog, imm_b(nfp_prog),
return 0; reg_a(dst_gpr), ALU_OP_AND, tmp_reg);
} /* Upper word of the mask can only be 0 or ~0 from sign extension,
* so either ignore it or OR the whole thing in.
if (imm & ~0U) { */
tmp_reg = ur_load_imm_any(nfp_prog, imm & ~0U, imm_b(nfp_prog)); if (imm >> 32)
emit_alu(nfp_prog, reg_none(), emit_alu(nfp_prog, reg_none(),
reg_a(insn->dst_reg * 2), ALU_OP_AND, tmp_reg); reg_a(dst_gpr + 1), ALU_OP_OR, imm_b(nfp_prog));
emit_br(nfp_prog, BR_BNE, insn->off, 0); emit_br(nfp_prog, BR_BNE, insn->off, 0);
}
if (imm >> 32) {
tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog));
emit_alu(nfp_prog, reg_none(),
reg_a(insn->dst_reg * 2 + 1), ALU_OP_AND, tmp_reg);
emit_br(nfp_prog, BR_BNE, insn->off, 0);
}
return 0; return 0;
} }

Просмотреть файл

@ -23,6 +23,7 @@ struct bpf_prog;
struct bpf_map; struct bpf_map;
struct sock; struct sock;
struct seq_file; struct seq_file;
struct btf;
struct btf_type; struct btf_type;
/* map is generic key/value storage optionally accesible by eBPF programs */ /* map is generic key/value storage optionally accesible by eBPF programs */
@ -52,6 +53,7 @@ struct bpf_map_ops {
void (*map_seq_show_elem)(struct bpf_map *map, void *key, void (*map_seq_show_elem)(struct bpf_map *map, void *key,
struct seq_file *m); struct seq_file *m);
int (*map_check_btf)(const struct bpf_map *map, int (*map_check_btf)(const struct bpf_map *map,
const struct btf *btf,
const struct btf_type *key_type, const struct btf_type *key_type,
const struct btf_type *value_type); const struct btf_type *value_type);
}; };
@ -126,6 +128,7 @@ static inline bool bpf_map_support_seq_show(const struct bpf_map *map)
} }
int map_check_no_btf(const struct bpf_map *map, int map_check_no_btf(const struct bpf_map *map,
const struct btf *btf,
const struct btf_type *key_type, const struct btf_type *key_type,
const struct btf_type *value_type); const struct btf_type *value_type);

Просмотреть файл

@ -38,6 +38,7 @@ enum bpf_reg_liveness {
REG_LIVE_NONE = 0, /* reg hasn't been read or written this branch */ REG_LIVE_NONE = 0, /* reg hasn't been read or written this branch */
REG_LIVE_READ, /* reg was read, so we're sensitive to initial value */ REG_LIVE_READ, /* reg was read, so we're sensitive to initial value */
REG_LIVE_WRITTEN, /* reg was written first, screening off later reads */ REG_LIVE_WRITTEN, /* reg was written first, screening off later reads */
REG_LIVE_DONE = 4, /* liveness won't be updating this register anymore */
}; };
struct bpf_reg_state { struct bpf_reg_state {
@ -224,6 +225,7 @@ struct bpf_verifier_env {
bool allow_ptr_leaks; bool allow_ptr_leaks;
bool seen_direct_write; bool seen_direct_write;
struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */ struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
const struct bpf_line_info *prev_linfo;
struct bpf_verifier_log log; struct bpf_verifier_log log;
struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1]; struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1];
u32 subprog_cnt; u32 subprog_cnt;

Просмотреть файл

@ -7,6 +7,7 @@
#include <linux/types.h> #include <linux/types.h>
struct btf; struct btf;
struct btf_member;
struct btf_type; struct btf_type;
union bpf_attr; union bpf_attr;
@ -46,7 +47,9 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,
struct seq_file *m); struct seq_file *m);
int btf_get_fd_by_id(u32 id); int btf_get_fd_by_id(u32 id);
u32 btf_id(const struct btf *btf); u32 btf_id(const struct btf *btf);
bool btf_name_offset_valid(const struct btf *btf, u32 offset); bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
const struct btf_member *m,
u32 expected_offset, u32 expected_size);
#ifdef CONFIG_BPF_SYSCALL #ifdef CONFIG_BPF_SYSCALL
const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id);

Просмотреть файл

@ -432,6 +432,10 @@ struct module {
unsigned int num_tracepoints; unsigned int num_tracepoints;
tracepoint_ptr_t *tracepoints_ptrs; tracepoint_ptr_t *tracepoints_ptrs;
#endif #endif
#ifdef CONFIG_BPF_EVENTS
unsigned int num_bpf_raw_events;
struct bpf_raw_event_map *bpf_raw_events;
#endif
#ifdef HAVE_JUMP_LABEL #ifdef HAVE_JUMP_LABEL
struct jump_entry *jump_entries; struct jump_entry *jump_entries;
unsigned int num_jump_entries; unsigned int num_jump_entries;

Просмотреть файл

@ -36,6 +36,7 @@ struct sk_msg_sg {
struct scatterlist data[MAX_MSG_FRAGS + 1]; struct scatterlist data[MAX_MSG_FRAGS + 1];
}; };
/* UAPI in filter.c depends on struct sk_msg_sg being first element. */
struct sk_msg { struct sk_msg {
struct sk_msg_sg sg; struct sk_msg_sg sg;
void *data; void *data;
@ -416,6 +417,14 @@ static inline void sk_psock_put(struct sock *sk, struct sk_psock *psock)
sk_psock_drop(sk, psock); sk_psock_drop(sk, psock);
} }
static inline void sk_psock_data_ready(struct sock *sk, struct sk_psock *psock)
{
if (psock->parser.enabled)
psock->parser.saved_data_ready(sk);
else
sk->sk_data_ready(sk);
}
static inline void psock_set_prog(struct bpf_prog **pprog, static inline void psock_set_prog(struct bpf_prog **pprog,
struct bpf_prog *prog) struct bpf_prog *prog)
{ {

Просмотреть файл

@ -286,6 +286,7 @@ struct ucred {
#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */ #define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */
#define MSG_MORE 0x8000 /* Sender will send more */ #define MSG_MORE 0x8000 /* Sender will send more */
#define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */ #define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */
#define MSG_SENDPAGE_NOPOLICY 0x10000 /* sendpage() internal : do no apply policy */
#define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */ #define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */
#define MSG_BATCH 0x40000 /* sendmmsg(): more messages coming */ #define MSG_BATCH 0x40000 /* sendmmsg(): more messages coming */
#define MSG_EOF MSG_FIN #define MSG_EOF MSG_FIN

Просмотреть файл

@ -471,7 +471,8 @@ void perf_event_detach_bpf_prog(struct perf_event *event);
int perf_event_query_prog_array(struct perf_event *event, void __user *info); int perf_event_query_prog_array(struct perf_event *event, void __user *info);
int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog); int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog);
int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog); int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_prog *prog);
struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name); struct bpf_raw_event_map *bpf_get_raw_tracepoint(const char *name);
void bpf_put_raw_tracepoint(struct bpf_raw_event_map *btp);
int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id, int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
u32 *fd_type, const char **buf, u32 *fd_type, const char **buf,
u64 *probe_offset, u64 *probe_addr); u64 *probe_offset, u64 *probe_addr);
@ -502,10 +503,13 @@ static inline int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name) static inline struct bpf_raw_event_map *bpf_get_raw_tracepoint(const char *name)
{ {
return NULL; return NULL;
} }
static inline void bpf_put_raw_tracepoint(struct bpf_raw_event_map *btp)
{
}
static inline int bpf_get_perf_event_info(const struct perf_event *event, static inline int bpf_get_perf_event_info(const struct perf_event *event,
u32 *prog_id, u32 *fd_type, u32 *prog_id, u32 *fd_type,
const char **buf, u64 *probe_offset, const char **buf, u64 *probe_offset,

Просмотреть файл

@ -460,6 +460,15 @@ tls_offload_ctx_tx(const struct tls_context *tls_ctx)
return (struct tls_offload_context_tx *)tls_ctx->priv_ctx_tx; return (struct tls_offload_context_tx *)tls_ctx->priv_ctx_tx;
} }
static inline bool tls_sw_has_ctx_tx(const struct sock *sk)
{
struct tls_context *ctx = tls_get_ctx(sk);
if (!ctx)
return false;
return !!tls_sw_ctx_tx(ctx);
}
static inline struct tls_offload_context_rx * static inline struct tls_offload_context_rx *
tls_offload_ctx_rx(const struct tls_context *tls_ctx) tls_offload_ctx_rx(const struct tls_context *tls_ctx)
{ {

Просмотреть файл

@ -133,6 +133,14 @@ enum bpf_map_type {
BPF_MAP_TYPE_STACK, BPF_MAP_TYPE_STACK,
}; };
/* Note that tracing related programs such as
* BPF_PROG_TYPE_{KPROBE,TRACEPOINT,PERF_EVENT,RAW_TRACEPOINT}
* are not subject to a stable API since kernel internal data
* structures can change from release to release and may
* therefore break existing tracing BPF programs. Tracing BPF
* programs correspond to /a/ specific kernel which is to be
* analyzed, and not /a/ specific kernel /and/ all future ones.
*/
enum bpf_prog_type { enum bpf_prog_type {
BPF_PROG_TYPE_UNSPEC, BPF_PROG_TYPE_UNSPEC,
BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_SOCKET_FILTER,
@ -343,7 +351,7 @@ union bpf_attr {
__u32 log_level; /* verbosity level of verifier */ __u32 log_level; /* verbosity level of verifier */
__u32 log_size; /* size of user buffer */ __u32 log_size; /* size of user buffer */
__aligned_u64 log_buf; /* user supplied buffer */ __aligned_u64 log_buf; /* user supplied buffer */
__u32 kern_version; /* checked when prog_type=kprobe */ __u32 kern_version; /* not used */
__u32 prog_flags; __u32 prog_flags;
char prog_name[BPF_OBJ_NAME_LEN]; char prog_name[BPF_OBJ_NAME_LEN];
__u32 prog_ifindex; /* ifindex of netdev to prep for */ __u32 prog_ifindex; /* ifindex of netdev to prep for */
@ -2657,6 +2665,7 @@ struct sk_msg_md {
__u32 local_ip6[4]; /* Stored in network byte order */ __u32 local_ip6[4]; /* Stored in network byte order */
__u32 remote_port; /* Stored in network byte order */ __u32 remote_port; /* Stored in network byte order */
__u32 local_port; /* stored in host byte order */ __u32 local_port; /* stored in host byte order */
__u32 size; /* Total size of sk_msg */
}; };
struct sk_reuseport_md { struct sk_reuseport_md {
@ -2717,6 +2726,8 @@ struct bpf_prog_info {
__u32 nr_jited_line_info; __u32 nr_jited_line_info;
__u32 line_info_rec_size; __u32 line_info_rec_size;
__u32 jited_line_info_rec_size; __u32 jited_line_info_rec_size;
__u32 nr_prog_tags;
__aligned_u64 prog_tags;
} __attribute__((aligned(8))); } __attribute__((aligned(8)));
struct bpf_map_info { struct bpf_map_info {

Просмотреть файл

@ -34,7 +34,9 @@ struct btf_type {
* bits 0-15: vlen (e.g. # of struct's members) * bits 0-15: vlen (e.g. # of struct's members)
* bits 16-23: unused * bits 16-23: unused
* bits 24-27: kind (e.g. int, ptr, array...etc) * bits 24-27: kind (e.g. int, ptr, array...etc)
* bits 28-31: unused * bits 28-30: unused
* bit 31: kind_flag, currently used by
* struct, union and fwd
*/ */
__u32 info; __u32 info;
/* "size" is used by INT, ENUM, STRUCT and UNION. /* "size" is used by INT, ENUM, STRUCT and UNION.
@ -52,6 +54,7 @@ struct btf_type {
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f) #define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
#define BTF_INFO_VLEN(info) ((info) & 0xffff) #define BTF_INFO_VLEN(info) ((info) & 0xffff)
#define BTF_INFO_KFLAG(info) ((info) >> 31)
#define BTF_KIND_UNKN 0 /* Unknown */ #define BTF_KIND_UNKN 0 /* Unknown */
#define BTF_KIND_INT 1 /* Integer */ #define BTF_KIND_INT 1 /* Integer */
@ -110,9 +113,22 @@ struct btf_array {
struct btf_member { struct btf_member {
__u32 name_off; __u32 name_off;
__u32 type; __u32 type;
__u32 offset; /* offset in bits */ /* If the type info kind_flag is set, the btf_member offset
* contains both member bitfield size and bit offset. The
* bitfield size is set for bitfield members. If the type
* info kind_flag is not set, the offset contains only bit
* offset.
*/
__u32 offset;
}; };
/* If the struct/union type info kind_flag is set, the
* following two macros are used to access bitfield_size
* and bit_offset from btf_member.offset.
*/
#define BTF_MEMBER_BITFIELD_SIZE(val) ((val) >> 24)
#define BTF_MEMBER_BIT_OFFSET(val) ((val) & 0xffffff)
/* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param". /* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
* The exact number of btf_param is stored in the vlen (of the * The exact number of btf_param is stored in the vlen (of the
* info in "struct btf_type"). * info in "struct btf_type").

Просмотреть файл

@ -382,6 +382,7 @@ static void percpu_array_map_seq_show_elem(struct bpf_map *map, void *key,
} }
static int array_map_check_btf(const struct bpf_map *map, static int array_map_check_btf(const struct bpf_map *map,
const struct btf *btf,
const struct btf_type *key_type, const struct btf_type *key_type,
const struct btf_type *value_type) const struct btf_type *value_type)
{ {

Просмотреть файл

@ -164,7 +164,7 @@
#define BITS_ROUNDUP_BYTES(bits) \ #define BITS_ROUNDUP_BYTES(bits) \
(BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits)) (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
#define BTF_INFO_MASK 0x0f00ffff #define BTF_INFO_MASK 0x8f00ffff
#define BTF_INT_MASK 0x0fffffff #define BTF_INT_MASK 0x0fffffff
#define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE) #define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE)
#define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET) #define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET)
@ -274,6 +274,10 @@ struct btf_kind_operations {
const struct btf_type *struct_type, const struct btf_type *struct_type,
const struct btf_member *member, const struct btf_member *member,
const struct btf_type *member_type); const struct btf_type *member_type);
int (*check_kflag_member)(struct btf_verifier_env *env,
const struct btf_type *struct_type,
const struct btf_member *member,
const struct btf_type *member_type);
void (*log_details)(struct btf_verifier_env *env, void (*log_details)(struct btf_verifier_env *env,
const struct btf_type *t); const struct btf_type *t);
void (*seq_show)(const struct btf *btf, const struct btf_type *t, void (*seq_show)(const struct btf *btf, const struct btf_type *t,
@ -419,6 +423,25 @@ static u16 btf_type_vlen(const struct btf_type *t)
return BTF_INFO_VLEN(t->info); return BTF_INFO_VLEN(t->info);
} }
static bool btf_type_kflag(const struct btf_type *t)
{
return BTF_INFO_KFLAG(t->info);
}
static u32 btf_member_bit_offset(const struct btf_type *struct_type,
const struct btf_member *member)
{
return btf_type_kflag(struct_type) ? BTF_MEMBER_BIT_OFFSET(member->offset)
: member->offset;
}
static u32 btf_member_bitfield_size(const struct btf_type *struct_type,
const struct btf_member *member)
{
return btf_type_kflag(struct_type) ? BTF_MEMBER_BITFIELD_SIZE(member->offset)
: 0;
}
static u32 btf_type_int(const struct btf_type *t) static u32 btf_type_int(const struct btf_type *t)
{ {
return *(u32 *)(t + 1); return *(u32 *)(t + 1);
@ -474,7 +497,7 @@ static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
return !*src; return !*src;
} }
const char *btf_name_by_offset(const struct btf *btf, u32 offset) static const char *__btf_name_by_offset(const struct btf *btf, u32 offset)
{ {
if (!offset) if (!offset)
return "(anon)"; return "(anon)";
@ -484,6 +507,14 @@ const char *btf_name_by_offset(const struct btf *btf, u32 offset)
return "(invalid-name-offset)"; return "(invalid-name-offset)";
} }
const char *btf_name_by_offset(const struct btf *btf, u32 offset)
{
if (offset < btf->hdr.str_len)
return &btf->strings[offset];
return NULL;
}
const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id) const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id)
{ {
if (type_id > btf->nr_types) if (type_id > btf->nr_types)
@ -514,6 +545,47 @@ static bool btf_type_int_is_regular(const struct btf_type *t)
return true; return true;
} }
/*
* Check that given struct member is a regular int with expected
* offset and size.
*/
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
const struct btf_member *m,
u32 expected_offset, u32 expected_size)
{
const struct btf_type *t;
u32 id, int_data;
u8 nr_bits;
id = m->type;
t = btf_type_id_size(btf, &id, NULL);
if (!t || !btf_type_is_int(t))
return false;
int_data = btf_type_int(t);
nr_bits = BTF_INT_BITS(int_data);
if (btf_type_kflag(s)) {
u32 bitfield_size = BTF_MEMBER_BITFIELD_SIZE(m->offset);
u32 bit_offset = BTF_MEMBER_BIT_OFFSET(m->offset);
/* if kflag set, int should be a regular int and
* bit offset should be at byte boundary.
*/
return !bitfield_size &&
BITS_ROUNDUP_BYTES(bit_offset) == expected_offset &&
BITS_ROUNDUP_BYTES(nr_bits) == expected_size;
}
if (BTF_INT_OFFSET(int_data) ||
BITS_PER_BYTE_MASKED(m->offset) ||
BITS_ROUNDUP_BYTES(m->offset) != expected_offset ||
BITS_PER_BYTE_MASKED(nr_bits) ||
BITS_ROUNDUP_BYTES(nr_bits) != expected_size)
return false;
return true;
}
__printf(2, 3) static void __btf_verifier_log(struct bpf_verifier_log *log, __printf(2, 3) static void __btf_verifier_log(struct bpf_verifier_log *log,
const char *fmt, ...) const char *fmt, ...)
{ {
@ -554,7 +626,7 @@ __printf(4, 5) static void __btf_verifier_log_type(struct btf_verifier_env *env,
__btf_verifier_log(log, "[%u] %s %s%s", __btf_verifier_log(log, "[%u] %s %s%s",
env->log_type_id, env->log_type_id,
btf_kind_str[kind], btf_kind_str[kind],
btf_name_by_offset(btf, t->name_off), __btf_name_by_offset(btf, t->name_off),
log_details ? " " : ""); log_details ? " " : "");
if (log_details) if (log_details)
@ -597,9 +669,17 @@ static void btf_verifier_log_member(struct btf_verifier_env *env,
if (env->phase != CHECK_META) if (env->phase != CHECK_META)
btf_verifier_log_type(env, struct_type, NULL); btf_verifier_log_type(env, struct_type, NULL);
__btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u", if (btf_type_kflag(struct_type))
btf_name_by_offset(btf, member->name_off), __btf_verifier_log(log,
member->type, member->offset); "\t%s type_id=%u bitfield_size=%u bits_offset=%u",
__btf_name_by_offset(btf, member->name_off),
member->type,
BTF_MEMBER_BITFIELD_SIZE(member->offset),
BTF_MEMBER_BIT_OFFSET(member->offset));
else
__btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u",
__btf_name_by_offset(btf, member->name_off),
member->type, member->offset);
if (fmt && *fmt) { if (fmt && *fmt) {
__btf_verifier_log(log, " "); __btf_verifier_log(log, " ");
@ -915,6 +995,38 @@ static int btf_df_check_member(struct btf_verifier_env *env,
return -EINVAL; return -EINVAL;
} }
static int btf_df_check_kflag_member(struct btf_verifier_env *env,
const struct btf_type *struct_type,
const struct btf_member *member,
const struct btf_type *member_type)
{
btf_verifier_log_basic(env, struct_type,
"Unsupported check_kflag_member");
return -EINVAL;
}
/* Used for ptr, array and struct/union type members.
* int, enum and modifier types have their specific callback functions.
*/
static int btf_generic_check_kflag_member(struct btf_verifier_env *env,
const struct btf_type *struct_type,
const struct btf_member *member,
const struct btf_type *member_type)
{
if (BTF_MEMBER_BITFIELD_SIZE(member->offset)) {
btf_verifier_log_member(env, struct_type, member,
"Invalid member bitfield_size");
return -EINVAL;
}
/* bitfield size is 0, so member->offset represents bit offset only.
* It is safe to call non kflag check_member variants.
*/
return btf_type_ops(member_type)->check_member(env, struct_type,
member,
member_type);
}
static int btf_df_resolve(struct btf_verifier_env *env, static int btf_df_resolve(struct btf_verifier_env *env,
const struct resolve_vertex *v) const struct resolve_vertex *v)
{ {
@ -967,6 +1079,62 @@ static int btf_int_check_member(struct btf_verifier_env *env,
return 0; return 0;
} }
static int btf_int_check_kflag_member(struct btf_verifier_env *env,
const struct btf_type *struct_type,
const struct btf_member *member,
const struct btf_type *member_type)
{
u32 struct_bits_off, nr_bits, nr_int_data_bits, bytes_offset;
u32 int_data = btf_type_int(member_type);
u32 struct_size = struct_type->size;
u32 nr_copy_bits;
/* a regular int type is required for the kflag int member */
if (!btf_type_int_is_regular(member_type)) {
btf_verifier_log_member(env, struct_type, member,
"Invalid member base type");
return -EINVAL;
}
/* check sanity of bitfield size */
nr_bits = BTF_MEMBER_BITFIELD_SIZE(member->offset);
struct_bits_off = BTF_MEMBER_BIT_OFFSET(member->offset);
nr_int_data_bits = BTF_INT_BITS(int_data);
if (!nr_bits) {
/* Not a bitfield member, member offset must be at byte
* boundary.
*/
if (BITS_PER_BYTE_MASKED(struct_bits_off)) {
btf_verifier_log_member(env, struct_type, member,
"Invalid member offset");
return -EINVAL;
}
nr_bits = nr_int_data_bits;
} else if (nr_bits > nr_int_data_bits) {
btf_verifier_log_member(env, struct_type, member,
"Invalid member bitfield_size");
return -EINVAL;
}
bytes_offset = BITS_ROUNDDOWN_BYTES(struct_bits_off);
nr_copy_bits = nr_bits + BITS_PER_BYTE_MASKED(struct_bits_off);
if (nr_copy_bits > BITS_PER_U64) {
btf_verifier_log_member(env, struct_type, member,
"nr_copy_bits exceeds 64");
return -EINVAL;
}
if (struct_size < bytes_offset ||
struct_size - bytes_offset < BITS_ROUNDUP_BYTES(nr_copy_bits)) {
btf_verifier_log_member(env, struct_type, member,
"Member exceeds struct_size");
return -EINVAL;
}
return 0;
}
static s32 btf_int_check_meta(struct btf_verifier_env *env, static s32 btf_int_check_meta(struct btf_verifier_env *env,
const struct btf_type *t, const struct btf_type *t,
u32 meta_left) u32 meta_left)
@ -986,6 +1154,11 @@ static s32 btf_int_check_meta(struct btf_verifier_env *env,
return -EINVAL; return -EINVAL;
} }
if (btf_type_kflag(t)) {
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
return -EINVAL;
}
int_data = btf_type_int(t); int_data = btf_type_int(t);
if (int_data & ~BTF_INT_MASK) { if (int_data & ~BTF_INT_MASK) {
btf_verifier_log_basic(env, t, "Invalid int_data:%x", btf_verifier_log_basic(env, t, "Invalid int_data:%x",
@ -1038,26 +1211,16 @@ static void btf_int_log(struct btf_verifier_env *env,
btf_int_encoding_str(BTF_INT_ENCODING(int_data))); btf_int_encoding_str(BTF_INT_ENCODING(int_data)));
} }
static void btf_int_bits_seq_show(const struct btf *btf, static void btf_bitfield_seq_show(void *data, u8 bits_offset,
const struct btf_type *t, u8 nr_bits, struct seq_file *m)
void *data, u8 bits_offset,
struct seq_file *m)
{ {
u16 left_shift_bits, right_shift_bits; u16 left_shift_bits, right_shift_bits;
u32 int_data = btf_type_int(t);
u8 nr_bits = BTF_INT_BITS(int_data);
u8 total_bits_offset;
u8 nr_copy_bytes; u8 nr_copy_bytes;
u8 nr_copy_bits; u8 nr_copy_bits;
u64 print_num; u64 print_num;
/* data += BITS_ROUNDDOWN_BYTES(bits_offset);
* bits_offset is at most 7. bits_offset = BITS_PER_BYTE_MASKED(bits_offset);
* BTF_INT_OFFSET() cannot exceed 64 bits.
*/
total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data);
data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
bits_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
nr_copy_bits = nr_bits + bits_offset; nr_copy_bits = nr_bits + bits_offset;
nr_copy_bytes = BITS_ROUNDUP_BYTES(nr_copy_bits); nr_copy_bytes = BITS_ROUNDUP_BYTES(nr_copy_bits);
@ -1077,6 +1240,24 @@ static void btf_int_bits_seq_show(const struct btf *btf,
seq_printf(m, "0x%llx", print_num); seq_printf(m, "0x%llx", print_num);
} }
static void btf_int_bits_seq_show(const struct btf *btf,
const struct btf_type *t,
void *data, u8 bits_offset,
struct seq_file *m)
{
u32 int_data = btf_type_int(t);
u8 nr_bits = BTF_INT_BITS(int_data);
u8 total_bits_offset;
/*
* bits_offset is at most 7.
* BTF_INT_OFFSET() cannot exceed 64 bits.
*/
total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data);
btf_bitfield_seq_show(data, total_bits_offset, nr_bits, m);
}
static void btf_int_seq_show(const struct btf *btf, const struct btf_type *t, static void btf_int_seq_show(const struct btf *btf, const struct btf_type *t,
u32 type_id, void *data, u8 bits_offset, u32 type_id, void *data, u8 bits_offset,
struct seq_file *m) struct seq_file *m)
@ -1126,6 +1307,7 @@ static const struct btf_kind_operations int_ops = {
.check_meta = btf_int_check_meta, .check_meta = btf_int_check_meta,
.resolve = btf_df_resolve, .resolve = btf_df_resolve,
.check_member = btf_int_check_member, .check_member = btf_int_check_member,
.check_kflag_member = btf_int_check_kflag_member,
.log_details = btf_int_log, .log_details = btf_int_log,
.seq_show = btf_int_seq_show, .seq_show = btf_int_seq_show,
}; };
@ -1155,6 +1337,31 @@ static int btf_modifier_check_member(struct btf_verifier_env *env,
resolved_type); resolved_type);
} }
static int btf_modifier_check_kflag_member(struct btf_verifier_env *env,
const struct btf_type *struct_type,
const struct btf_member *member,
const struct btf_type *member_type)
{
const struct btf_type *resolved_type;
u32 resolved_type_id = member->type;
struct btf_member resolved_member;
struct btf *btf = env->btf;
resolved_type = btf_type_id_size(btf, &resolved_type_id, NULL);
if (!resolved_type) {
btf_verifier_log_member(env, struct_type, member,
"Invalid member");
return -EINVAL;
}
resolved_member = *member;
resolved_member.type = resolved_type_id;
return btf_type_ops(resolved_type)->check_kflag_member(env, struct_type,
&resolved_member,
resolved_type);
}
static int btf_ptr_check_member(struct btf_verifier_env *env, static int btf_ptr_check_member(struct btf_verifier_env *env,
const struct btf_type *struct_type, const struct btf_type *struct_type,
const struct btf_member *member, const struct btf_member *member,
@ -1190,6 +1397,11 @@ static int btf_ref_type_check_meta(struct btf_verifier_env *env,
return -EINVAL; return -EINVAL;
} }
if (btf_type_kflag(t)) {
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
return -EINVAL;
}
if (!BTF_TYPE_ID_VALID(t->type)) { if (!BTF_TYPE_ID_VALID(t->type)) {
btf_verifier_log_type(env, t, "Invalid type_id"); btf_verifier_log_type(env, t, "Invalid type_id");
return -EINVAL; return -EINVAL;
@ -1343,6 +1555,7 @@ static struct btf_kind_operations modifier_ops = {
.check_meta = btf_ref_type_check_meta, .check_meta = btf_ref_type_check_meta,
.resolve = btf_modifier_resolve, .resolve = btf_modifier_resolve,
.check_member = btf_modifier_check_member, .check_member = btf_modifier_check_member,
.check_kflag_member = btf_modifier_check_kflag_member,
.log_details = btf_ref_type_log, .log_details = btf_ref_type_log,
.seq_show = btf_modifier_seq_show, .seq_show = btf_modifier_seq_show,
}; };
@ -1351,6 +1564,7 @@ static struct btf_kind_operations ptr_ops = {
.check_meta = btf_ref_type_check_meta, .check_meta = btf_ref_type_check_meta,
.resolve = btf_ptr_resolve, .resolve = btf_ptr_resolve,
.check_member = btf_ptr_check_member, .check_member = btf_ptr_check_member,
.check_kflag_member = btf_generic_check_kflag_member,
.log_details = btf_ref_type_log, .log_details = btf_ref_type_log,
.seq_show = btf_ptr_seq_show, .seq_show = btf_ptr_seq_show,
}; };
@ -1381,11 +1595,18 @@ static s32 btf_fwd_check_meta(struct btf_verifier_env *env,
return 0; return 0;
} }
static void btf_fwd_type_log(struct btf_verifier_env *env,
const struct btf_type *t)
{
btf_verifier_log(env, "%s", btf_type_kflag(t) ? "union" : "struct");
}
static struct btf_kind_operations fwd_ops = { static struct btf_kind_operations fwd_ops = {
.check_meta = btf_fwd_check_meta, .check_meta = btf_fwd_check_meta,
.resolve = btf_df_resolve, .resolve = btf_df_resolve,
.check_member = btf_df_check_member, .check_member = btf_df_check_member,
.log_details = btf_ref_type_log, .check_kflag_member = btf_df_check_kflag_member,
.log_details = btf_fwd_type_log,
.seq_show = btf_df_seq_show, .seq_show = btf_df_seq_show,
}; };
@ -1443,6 +1664,11 @@ static s32 btf_array_check_meta(struct btf_verifier_env *env,
return -EINVAL; return -EINVAL;
} }
if (btf_type_kflag(t)) {
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
return -EINVAL;
}
if (t->size) { if (t->size) {
btf_verifier_log_type(env, t, "size != 0"); btf_verifier_log_type(env, t, "size != 0");
return -EINVAL; return -EINVAL;
@ -1566,6 +1792,7 @@ static struct btf_kind_operations array_ops = {
.check_meta = btf_array_check_meta, .check_meta = btf_array_check_meta,
.resolve = btf_array_resolve, .resolve = btf_array_resolve,
.check_member = btf_array_check_member, .check_member = btf_array_check_member,
.check_kflag_member = btf_generic_check_kflag_member,
.log_details = btf_array_log, .log_details = btf_array_log,
.seq_show = btf_array_seq_show, .seq_show = btf_array_seq_show,
}; };
@ -1604,6 +1831,7 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
u32 meta_needed, last_offset; u32 meta_needed, last_offset;
struct btf *btf = env->btf; struct btf *btf = env->btf;
u32 struct_size = t->size; u32 struct_size = t->size;
u32 offset;
u16 i; u16 i;
meta_needed = btf_type_vlen(t) * sizeof(*member); meta_needed = btf_type_vlen(t) * sizeof(*member);
@ -1645,7 +1873,8 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
return -EINVAL; return -EINVAL;
} }
if (is_union && member->offset) { offset = btf_member_bit_offset(t, member);
if (is_union && offset) {
btf_verifier_log_member(env, t, member, btf_verifier_log_member(env, t, member,
"Invalid member bits_offset"); "Invalid member bits_offset");
return -EINVAL; return -EINVAL;
@ -1655,20 +1884,20 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env,
* ">" instead of ">=" because the last member could be * ">" instead of ">=" because the last member could be
* "char a[0];" * "char a[0];"
*/ */
if (last_offset > member->offset) { if (last_offset > offset) {
btf_verifier_log_member(env, t, member, btf_verifier_log_member(env, t, member,
"Invalid member bits_offset"); "Invalid member bits_offset");
return -EINVAL; return -EINVAL;
} }
if (BITS_ROUNDUP_BYTES(member->offset) > struct_size) { if (BITS_ROUNDUP_BYTES(offset) > struct_size) {
btf_verifier_log_member(env, t, member, btf_verifier_log_member(env, t, member,
"Member bits_offset exceeds its struct size"); "Member bits_offset exceeds its struct size");
return -EINVAL; return -EINVAL;
} }
btf_verifier_log_member(env, t, member, NULL); btf_verifier_log_member(env, t, member, NULL);
last_offset = member->offset; last_offset = offset;
} }
return meta_needed; return meta_needed;
@ -1698,9 +1927,14 @@ static int btf_struct_resolve(struct btf_verifier_env *env,
last_member_type = btf_type_by_id(env->btf, last_member_type = btf_type_by_id(env->btf,
last_member_type_id); last_member_type_id);
err = btf_type_ops(last_member_type)->check_member(env, v->t, if (btf_type_kflag(v->t))
last_member, err = btf_type_ops(last_member_type)->check_kflag_member(env, v->t,
last_member_type); last_member,
last_member_type);
else
err = btf_type_ops(last_member_type)->check_member(env, v->t,
last_member,
last_member_type);
if (err) if (err)
return err; return err;
} }
@ -1722,9 +1956,14 @@ static int btf_struct_resolve(struct btf_verifier_env *env,
return env_stack_push(env, member_type, member_type_id); return env_stack_push(env, member_type, member_type_id);
} }
err = btf_type_ops(member_type)->check_member(env, v->t, if (btf_type_kflag(v->t))
member, err = btf_type_ops(member_type)->check_kflag_member(env, v->t,
member_type); member,
member_type);
else
err = btf_type_ops(member_type)->check_member(env, v->t,
member,
member_type);
if (err) if (err)
return err; return err;
} }
@ -1752,17 +1991,26 @@ static void btf_struct_seq_show(const struct btf *btf, const struct btf_type *t,
for_each_member(i, t, member) { for_each_member(i, t, member) {
const struct btf_type *member_type = btf_type_by_id(btf, const struct btf_type *member_type = btf_type_by_id(btf,
member->type); member->type);
u32 member_offset = member->offset;
u32 bytes_offset = BITS_ROUNDDOWN_BYTES(member_offset);
u8 bits8_offset = BITS_PER_BYTE_MASKED(member_offset);
const struct btf_kind_operations *ops; const struct btf_kind_operations *ops;
u32 member_offset, bitfield_size;
u32 bytes_offset;
u8 bits8_offset;
if (i) if (i)
seq_puts(m, seq); seq_puts(m, seq);
ops = btf_type_ops(member_type); member_offset = btf_member_bit_offset(t, member);
ops->seq_show(btf, member_type, member->type, bitfield_size = btf_member_bitfield_size(t, member);
data + bytes_offset, bits8_offset, m); if (bitfield_size) {
btf_bitfield_seq_show(data, member_offset,
bitfield_size, m);
} else {
bytes_offset = BITS_ROUNDDOWN_BYTES(member_offset);
bits8_offset = BITS_PER_BYTE_MASKED(member_offset);
ops = btf_type_ops(member_type);
ops->seq_show(btf, member_type, member->type,
data + bytes_offset, bits8_offset, m);
}
} }
seq_puts(m, "}"); seq_puts(m, "}");
} }
@ -1771,6 +2019,7 @@ static struct btf_kind_operations struct_ops = {
.check_meta = btf_struct_check_meta, .check_meta = btf_struct_check_meta,
.resolve = btf_struct_resolve, .resolve = btf_struct_resolve,
.check_member = btf_struct_check_member, .check_member = btf_struct_check_member,
.check_kflag_member = btf_generic_check_kflag_member,
.log_details = btf_struct_log, .log_details = btf_struct_log,
.seq_show = btf_struct_seq_show, .seq_show = btf_struct_seq_show,
}; };
@ -1800,6 +2049,41 @@ static int btf_enum_check_member(struct btf_verifier_env *env,
return 0; return 0;
} }
static int btf_enum_check_kflag_member(struct btf_verifier_env *env,
const struct btf_type *struct_type,
const struct btf_member *member,
const struct btf_type *member_type)
{
u32 struct_bits_off, nr_bits, bytes_end, struct_size;
u32 int_bitsize = sizeof(int) * BITS_PER_BYTE;
struct_bits_off = BTF_MEMBER_BIT_OFFSET(member->offset);
nr_bits = BTF_MEMBER_BITFIELD_SIZE(member->offset);
if (!nr_bits) {
if (BITS_PER_BYTE_MASKED(struct_bits_off)) {
btf_verifier_log_member(env, struct_type, member,
"Member is not byte aligned");
return -EINVAL;
}
nr_bits = int_bitsize;
} else if (nr_bits > int_bitsize) {
btf_verifier_log_member(env, struct_type, member,
"Invalid member bitfield_size");
return -EINVAL;
}
struct_size = struct_type->size;
bytes_end = BITS_ROUNDUP_BYTES(struct_bits_off + nr_bits);
if (struct_size < bytes_end) {
btf_verifier_log_member(env, struct_type, member,
"Member exceeds struct_size");
return -EINVAL;
}
return 0;
}
static s32 btf_enum_check_meta(struct btf_verifier_env *env, static s32 btf_enum_check_meta(struct btf_verifier_env *env,
const struct btf_type *t, const struct btf_type *t,
u32 meta_left) u32 meta_left)
@ -1819,6 +2103,11 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
return -EINVAL; return -EINVAL;
} }
if (btf_type_kflag(t)) {
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
return -EINVAL;
}
if (t->size != sizeof(int)) { if (t->size != sizeof(int)) {
btf_verifier_log_type(env, t, "Expected size:%zu", btf_verifier_log_type(env, t, "Expected size:%zu",
sizeof(int)); sizeof(int));
@ -1850,7 +2139,7 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
btf_verifier_log(env, "\t%s val=%d\n", btf_verifier_log(env, "\t%s val=%d\n",
btf_name_by_offset(btf, enums[i].name_off), __btf_name_by_offset(btf, enums[i].name_off),
enums[i].val); enums[i].val);
} }
@ -1874,7 +2163,8 @@ static void btf_enum_seq_show(const struct btf *btf, const struct btf_type *t,
for (i = 0; i < nr_enums; i++) { for (i = 0; i < nr_enums; i++) {
if (v == enums[i].val) { if (v == enums[i].val) {
seq_printf(m, "%s", seq_printf(m, "%s",
btf_name_by_offset(btf, enums[i].name_off)); __btf_name_by_offset(btf,
enums[i].name_off));
return; return;
} }
} }
@ -1886,6 +2176,7 @@ static struct btf_kind_operations enum_ops = {
.check_meta = btf_enum_check_meta, .check_meta = btf_enum_check_meta,
.resolve = btf_df_resolve, .resolve = btf_df_resolve,
.check_member = btf_enum_check_member, .check_member = btf_enum_check_member,
.check_kflag_member = btf_enum_check_kflag_member,
.log_details = btf_enum_log, .log_details = btf_enum_log,
.seq_show = btf_enum_seq_show, .seq_show = btf_enum_seq_show,
}; };
@ -1908,6 +2199,11 @@ static s32 btf_func_proto_check_meta(struct btf_verifier_env *env,
return -EINVAL; return -EINVAL;
} }
if (btf_type_kflag(t)) {
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
return -EINVAL;
}
btf_verifier_log_type(env, t, NULL); btf_verifier_log_type(env, t, NULL);
return meta_needed; return meta_needed;
@ -1932,20 +2228,20 @@ static void btf_func_proto_log(struct btf_verifier_env *env,
} }
btf_verifier_log(env, "%u %s", args[0].type, btf_verifier_log(env, "%u %s", args[0].type,
btf_name_by_offset(env->btf, __btf_name_by_offset(env->btf,
args[0].name_off)); args[0].name_off));
for (i = 1; i < nr_args - 1; i++) for (i = 1; i < nr_args - 1; i++)
btf_verifier_log(env, ", %u %s", args[i].type, btf_verifier_log(env, ", %u %s", args[i].type,
btf_name_by_offset(env->btf, __btf_name_by_offset(env->btf,
args[i].name_off)); args[i].name_off));
if (nr_args > 1) { if (nr_args > 1) {
const struct btf_param *last_arg = &args[nr_args - 1]; const struct btf_param *last_arg = &args[nr_args - 1];
if (last_arg->type) if (last_arg->type)
btf_verifier_log(env, ", %u %s", last_arg->type, btf_verifier_log(env, ", %u %s", last_arg->type,
btf_name_by_offset(env->btf, __btf_name_by_offset(env->btf,
last_arg->name_off)); last_arg->name_off));
else else
btf_verifier_log(env, ", vararg"); btf_verifier_log(env, ", vararg");
} }
@ -1967,6 +2263,7 @@ static struct btf_kind_operations func_proto_ops = {
* Hence, there is no btf_func_check_member(). * Hence, there is no btf_func_check_member().
*/ */
.check_member = btf_df_check_member, .check_member = btf_df_check_member,
.check_kflag_member = btf_df_check_kflag_member,
.log_details = btf_func_proto_log, .log_details = btf_func_proto_log,
.seq_show = btf_df_seq_show, .seq_show = btf_df_seq_show,
}; };
@ -1986,6 +2283,11 @@ static s32 btf_func_check_meta(struct btf_verifier_env *env,
return -EINVAL; return -EINVAL;
} }
if (btf_type_kflag(t)) {
btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
return -EINVAL;
}
btf_verifier_log_type(env, t, NULL); btf_verifier_log_type(env, t, NULL);
return 0; return 0;
@ -1995,6 +2297,7 @@ static struct btf_kind_operations func_ops = {
.check_meta = btf_func_check_meta, .check_meta = btf_func_check_meta,
.resolve = btf_df_resolve, .resolve = btf_df_resolve,
.check_member = btf_df_check_member, .check_member = btf_df_check_member,
.check_kflag_member = btf_df_check_kflag_member,
.log_details = btf_ref_type_log, .log_details = btf_ref_type_log,
.seq_show = btf_df_seq_show, .seq_show = btf_df_seq_show,
}; };

Просмотреть файл

@ -183,7 +183,7 @@ static struct sk_buff *cpu_map_build_skb(struct bpf_cpu_map_entry *rcpu,
* is not at a fixed memory location, with mixed length * is not at a fixed memory location, with mixed length
* packets, which is bad for cache-line hotness. * packets, which is bad for cache-line hotness.
*/ */
frame_size = SKB_DATA_ALIGN(xdpf->len) + xdpf->headroom + frame_size = SKB_DATA_ALIGN(xdpf->len + xdpf->headroom) +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
pkt_data_start = xdpf->data - xdpf->headroom; pkt_data_start = xdpf->data - xdpf->headroom;

Просмотреть файл

@ -1,11 +1,13 @@
//SPDX-License-Identifier: GPL-2.0 //SPDX-License-Identifier: GPL-2.0
#include <linux/bpf-cgroup.h> #include <linux/bpf-cgroup.h>
#include <linux/bpf.h> #include <linux/bpf.h>
#include <linux/btf.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/filter.h> #include <linux/filter.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <uapi/linux/btf.h>
DEFINE_PER_CPU(struct bpf_cgroup_storage*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); DEFINE_PER_CPU(struct bpf_cgroup_storage*, bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]);
@ -308,6 +310,85 @@ static int cgroup_storage_delete_elem(struct bpf_map *map, void *key)
return -EINVAL; return -EINVAL;
} }
static int cgroup_storage_check_btf(const struct bpf_map *map,
const struct btf *btf,
const struct btf_type *key_type,
const struct btf_type *value_type)
{
struct btf_member *m;
u32 offset, size;
/* Key is expected to be of struct bpf_cgroup_storage_key type,
* which is:
* struct bpf_cgroup_storage_key {
* __u64 cgroup_inode_id;
* __u32 attach_type;
* };
*/
/*
* Key_type must be a structure with two fields.
*/
if (BTF_INFO_KIND(key_type->info) != BTF_KIND_STRUCT ||
BTF_INFO_VLEN(key_type->info) != 2)
return -EINVAL;
/*
* The first field must be a 64 bit integer at 0 offset.
*/
m = (struct btf_member *)(key_type + 1);
size = FIELD_SIZEOF(struct bpf_cgroup_storage_key, cgroup_inode_id);
if (!btf_member_is_reg_int(btf, key_type, m, 0, size))
return -EINVAL;
/*
* The second field must be a 32 bit integer at 64 bit offset.
*/
m++;
offset = offsetof(struct bpf_cgroup_storage_key, attach_type);
size = FIELD_SIZEOF(struct bpf_cgroup_storage_key, attach_type);
if (!btf_member_is_reg_int(btf, key_type, m, offset, size))
return -EINVAL;
return 0;
}
static void cgroup_storage_seq_show_elem(struct bpf_map *map, void *_key,
struct seq_file *m)
{
enum bpf_cgroup_storage_type stype = cgroup_storage_type(map);
struct bpf_cgroup_storage_key *key = _key;
struct bpf_cgroup_storage *storage;
int cpu;
rcu_read_lock();
storage = cgroup_storage_lookup(map_to_storage(map), key, false);
if (!storage) {
rcu_read_unlock();
return;
}
btf_type_seq_show(map->btf, map->btf_key_type_id, key, m);
stype = cgroup_storage_type(map);
if (stype == BPF_CGROUP_STORAGE_SHARED) {
seq_puts(m, ": ");
btf_type_seq_show(map->btf, map->btf_value_type_id,
&READ_ONCE(storage->buf)->data[0], m);
seq_puts(m, "\n");
} else {
seq_puts(m, ": {\n");
for_each_possible_cpu(cpu) {
seq_printf(m, "\tcpu%d: ", cpu);
btf_type_seq_show(map->btf, map->btf_value_type_id,
per_cpu_ptr(storage->percpu_buf, cpu),
m);
seq_puts(m, "\n");
}
seq_puts(m, "}\n");
}
rcu_read_unlock();
}
const struct bpf_map_ops cgroup_storage_map_ops = { const struct bpf_map_ops cgroup_storage_map_ops = {
.map_alloc = cgroup_storage_map_alloc, .map_alloc = cgroup_storage_map_alloc,
.map_free = cgroup_storage_map_free, .map_free = cgroup_storage_map_free,
@ -315,7 +396,8 @@ const struct bpf_map_ops cgroup_storage_map_ops = {
.map_lookup_elem = cgroup_storage_lookup_elem, .map_lookup_elem = cgroup_storage_lookup_elem,
.map_update_elem = cgroup_storage_update_elem, .map_update_elem = cgroup_storage_update_elem,
.map_delete_elem = cgroup_storage_delete_elem, .map_delete_elem = cgroup_storage_delete_elem,
.map_check_btf = map_check_no_btf, .map_check_btf = cgroup_storage_check_btf,
.map_seq_show_elem = cgroup_storage_seq_show_elem,
}; };
int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map) int bpf_cgroup_storage_assign(struct bpf_prog *prog, struct bpf_map *_map)

Просмотреть файл

@ -728,6 +728,7 @@ free_stack:
} }
static int trie_check_btf(const struct bpf_map *map, static int trie_check_btf(const struct bpf_map *map,
const struct btf *btf,
const struct btf_type *key_type, const struct btf_type *key_type,
const struct btf_type *value_type) const struct btf_type *value_type)
{ {

Просмотреть файл

@ -456,6 +456,7 @@ static int bpf_obj_name_cpy(char *dst, const char *src)
} }
int map_check_no_btf(const struct bpf_map *map, int map_check_no_btf(const struct bpf_map *map,
const struct btf *btf,
const struct btf_type *key_type, const struct btf_type *key_type,
const struct btf_type *value_type) const struct btf_type *value_type)
{ {
@ -478,7 +479,7 @@ static int map_check_btf(const struct bpf_map *map, const struct btf *btf,
return -EINVAL; return -EINVAL;
if (map->ops->map_check_btf) if (map->ops->map_check_btf)
ret = map->ops->map_check_btf(map, key_type, value_type); ret = map->ops->map_check_btf(map, btf, key_type, value_type);
return ret; return ret;
} }
@ -1472,11 +1473,6 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS) if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS)
return -E2BIG; return -E2BIG;
if (type == BPF_PROG_TYPE_KPROBE &&
attr->kern_version != LINUX_VERSION_CODE)
return -EINVAL;
if (type != BPF_PROG_TYPE_SOCKET_FILTER && if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
type != BPF_PROG_TYPE_CGROUP_SKB && type != BPF_PROG_TYPE_CGROUP_SKB &&
!capable(CAP_SYS_ADMIN)) !capable(CAP_SYS_ADMIN))
@ -1608,6 +1604,7 @@ static int bpf_raw_tracepoint_release(struct inode *inode, struct file *filp)
bpf_probe_unregister(raw_tp->btp, raw_tp->prog); bpf_probe_unregister(raw_tp->btp, raw_tp->prog);
bpf_prog_put(raw_tp->prog); bpf_prog_put(raw_tp->prog);
} }
bpf_put_raw_tracepoint(raw_tp->btp);
kfree(raw_tp); kfree(raw_tp);
return 0; return 0;
} }
@ -1633,13 +1630,15 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
return -EFAULT; return -EFAULT;
tp_name[sizeof(tp_name) - 1] = 0; tp_name[sizeof(tp_name) - 1] = 0;
btp = bpf_find_raw_tracepoint(tp_name); btp = bpf_get_raw_tracepoint(tp_name);
if (!btp) if (!btp)
return -ENOENT; return -ENOENT;
raw_tp = kzalloc(sizeof(*raw_tp), GFP_USER); raw_tp = kzalloc(sizeof(*raw_tp), GFP_USER);
if (!raw_tp) if (!raw_tp) {
return -ENOMEM; err = -ENOMEM;
goto out_put_btp;
}
raw_tp->btp = btp; raw_tp->btp = btp;
prog = bpf_prog_get_type(attr->raw_tracepoint.prog_fd, prog = bpf_prog_get_type(attr->raw_tracepoint.prog_fd,
@ -1667,6 +1666,8 @@ out_put_prog:
bpf_prog_put(prog); bpf_prog_put(prog);
out_free_tp: out_free_tp:
kfree(raw_tp); kfree(raw_tp);
out_put_btp:
bpf_put_raw_tracepoint(btp);
return err; return err;
} }
@ -2031,13 +2032,6 @@ static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
insns[i + 1].imm = 0; insns[i + 1].imm = 0;
continue; continue;
} }
if (!bpf_dump_raw_ok() &&
imm == (unsigned long)prog->aux) {
insns[i].imm = 0;
insns[i + 1].imm = 0;
continue;
}
} }
return insns; return insns;
@ -2271,33 +2265,25 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
ulen = info.nr_func_info; ulen = info.nr_func_info;
info.nr_func_info = prog->aux->func_info_cnt; info.nr_func_info = prog->aux->func_info_cnt;
if (info.nr_func_info && ulen) { if (info.nr_func_info && ulen) {
if (bpf_dump_raw_ok()) { char __user *user_finfo;
char __user *user_finfo;
user_finfo = u64_to_user_ptr(info.func_info); user_finfo = u64_to_user_ptr(info.func_info);
ulen = min_t(u32, info.nr_func_info, ulen); ulen = min_t(u32, info.nr_func_info, ulen);
if (copy_to_user(user_finfo, prog->aux->func_info, if (copy_to_user(user_finfo, prog->aux->func_info,
info.func_info_rec_size * ulen)) info.func_info_rec_size * ulen))
return -EFAULT; return -EFAULT;
} else {
info.func_info = 0;
}
} }
ulen = info.nr_line_info; ulen = info.nr_line_info;
info.nr_line_info = prog->aux->nr_linfo; info.nr_line_info = prog->aux->nr_linfo;
if (info.nr_line_info && ulen) { if (info.nr_line_info && ulen) {
if (bpf_dump_raw_ok()) { __u8 __user *user_linfo;
__u8 __user *user_linfo;
user_linfo = u64_to_user_ptr(info.line_info); user_linfo = u64_to_user_ptr(info.line_info);
ulen = min_t(u32, info.nr_line_info, ulen); ulen = min_t(u32, info.nr_line_info, ulen);
if (copy_to_user(user_linfo, prog->aux->linfo, if (copy_to_user(user_linfo, prog->aux->linfo,
info.line_info_rec_size * ulen)) info.line_info_rec_size * ulen))
return -EFAULT; return -EFAULT;
} else {
info.line_info = 0;
}
} }
ulen = info.nr_jited_line_info; ulen = info.nr_jited_line_info;
@ -2322,6 +2308,28 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
} }
} }
ulen = info.nr_prog_tags;
info.nr_prog_tags = prog->aux->func_cnt ? : 1;
if (ulen) {
__u8 __user (*user_prog_tags)[BPF_TAG_SIZE];
u32 i;
user_prog_tags = u64_to_user_ptr(info.prog_tags);
ulen = min_t(u32, info.nr_prog_tags, ulen);
if (prog->aux->func_cnt) {
for (i = 0; i < ulen; i++) {
if (copy_to_user(user_prog_tags[i],
prog->aux->func[i]->tag,
BPF_TAG_SIZE))
return -EFAULT;
}
} else {
if (copy_to_user(user_prog_tags[0],
prog->tag, BPF_TAG_SIZE))
return -EFAULT;
}
}
done: done:
if (copy_to_user(uinfo, &info, info_len) || if (copy_to_user(uinfo, &info, info_len) ||
put_user(info_len, &uattr->info.info_len)) put_user(info_len, &uattr->info.info_len))

Просмотреть файл

@ -26,6 +26,7 @@
#include <linux/bsearch.h> #include <linux/bsearch.h>
#include <linux/sort.h> #include <linux/sort.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <linux/ctype.h>
#include "disasm.h" #include "disasm.h"
@ -216,6 +217,27 @@ struct bpf_call_arg_meta {
static DEFINE_MUTEX(bpf_verifier_lock); static DEFINE_MUTEX(bpf_verifier_lock);
static const struct bpf_line_info *
find_linfo(const struct bpf_verifier_env *env, u32 insn_off)
{
const struct bpf_line_info *linfo;
const struct bpf_prog *prog;
u32 i, nr_linfo;
prog = env->prog;
nr_linfo = prog->aux->nr_linfo;
if (!nr_linfo || insn_off >= prog->len)
return NULL;
linfo = prog->aux->linfo;
for (i = 1; i < nr_linfo; i++)
if (insn_off < linfo[i].insn_off)
break;
return &linfo[i - 1];
}
void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt, void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt,
va_list args) va_list args)
{ {
@ -266,6 +288,42 @@ __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...)
va_end(args); va_end(args);
} }
static const char *ltrim(const char *s)
{
while (isspace(*s))
s++;
return s;
}
__printf(3, 4) static void verbose_linfo(struct bpf_verifier_env *env,
u32 insn_off,
const char *prefix_fmt, ...)
{
const struct bpf_line_info *linfo;
if (!bpf_verifier_log_needed(&env->log))
return;
linfo = find_linfo(env, insn_off);
if (!linfo || linfo == env->prev_linfo)
return;
if (prefix_fmt) {
va_list args;
va_start(args, prefix_fmt);
bpf_verifier_vlog(&env->log, prefix_fmt, args);
va_end(args);
}
verbose(env, "%s\n",
ltrim(btf_name_by_offset(env->prog->aux->btf,
linfo->line_off)));
env->prev_linfo = linfo;
}
static bool type_is_pkt_pointer(enum bpf_reg_type type) static bool type_is_pkt_pointer(enum bpf_reg_type type)
{ {
return type == PTR_TO_PACKET || return type == PTR_TO_PACKET ||
@ -339,12 +397,14 @@ static char slot_type_char[] = {
static void print_liveness(struct bpf_verifier_env *env, static void print_liveness(struct bpf_verifier_env *env,
enum bpf_reg_liveness live) enum bpf_reg_liveness live)
{ {
if (live & (REG_LIVE_READ | REG_LIVE_WRITTEN)) if (live & (REG_LIVE_READ | REG_LIVE_WRITTEN | REG_LIVE_DONE))
verbose(env, "_"); verbose(env, "_");
if (live & REG_LIVE_READ) if (live & REG_LIVE_READ)
verbose(env, "r"); verbose(env, "r");
if (live & REG_LIVE_WRITTEN) if (live & REG_LIVE_WRITTEN)
verbose(env, "w"); verbose(env, "w");
if (live & REG_LIVE_DONE)
verbose(env, "D");
} }
static struct bpf_func_state *func(struct bpf_verifier_env *env, static struct bpf_func_state *func(struct bpf_verifier_env *env,
@ -1074,6 +1134,12 @@ static int mark_reg_read(struct bpf_verifier_env *env,
/* if read wasn't screened by an earlier write ... */ /* if read wasn't screened by an earlier write ... */
if (writes && state->live & REG_LIVE_WRITTEN) if (writes && state->live & REG_LIVE_WRITTEN)
break; break;
if (parent->live & REG_LIVE_DONE) {
verbose(env, "verifier BUG type %s var_off %lld off %d\n",
reg_type_str[parent->type],
parent->var_off.value, parent->off);
return -EFAULT;
}
/* ... then we depend on parent's value */ /* ... then we depend on parent's value */
parent->live |= REG_LIVE_READ; parent->live |= REG_LIVE_READ;
state = parent; state = parent;
@ -1220,6 +1286,10 @@ static int check_stack_write(struct bpf_verifier_env *env,
/* regular write of data into stack destroys any spilled ptr */ /* regular write of data into stack destroys any spilled ptr */
state->stack[spi].spilled_ptr.type = NOT_INIT; state->stack[spi].spilled_ptr.type = NOT_INIT;
/* Mark slots as STACK_MISC if they belonged to spilled ptr. */
if (state->stack[spi].slot_type[0] == STACK_SPILL)
for (i = 0; i < BPF_REG_SIZE; i++)
state->stack[spi].slot_type[i] = STACK_MISC;
/* only mark the slot as written if all 8 bytes were written /* only mark the slot as written if all 8 bytes were written
* otherwise read propagation may incorrectly stop too soon * otherwise read propagation may incorrectly stop too soon
@ -1237,6 +1307,7 @@ static int check_stack_write(struct bpf_verifier_env *env,
register_is_null(&cur->regs[value_regno])) register_is_null(&cur->regs[value_regno]))
type = STACK_ZERO; type = STACK_ZERO;
/* Mark slots affected by this stack write. */
for (i = 0; i < size; i++) for (i = 0; i < size; i++)
state->stack[spi].slot_type[(slot - i) % BPF_REG_SIZE] = state->stack[spi].slot_type[(slot - i) % BPF_REG_SIZE] =
type; type;
@ -3788,6 +3859,12 @@ static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode)
if (tnum_is_const(reg->var_off)) if (tnum_is_const(reg->var_off))
return !tnum_equals_const(reg->var_off, val); return !tnum_equals_const(reg->var_off, val);
break; break;
case BPF_JSET:
if ((~reg->var_off.mask & reg->var_off.value) & val)
return 1;
if (!((reg->var_off.mask | reg->var_off.value) & val))
return 0;
break;
case BPF_JGT: case BPF_JGT:
if (reg->umin_value > val) if (reg->umin_value > val)
return 1; return 1;
@ -3872,6 +3949,13 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
*/ */
__mark_reg_known(false_reg, val); __mark_reg_known(false_reg, val);
break; break;
case BPF_JSET:
false_reg->var_off = tnum_and(false_reg->var_off,
tnum_const(~val));
if (is_power_of_2(val))
true_reg->var_off = tnum_or(true_reg->var_off,
tnum_const(val));
break;
case BPF_JGT: case BPF_JGT:
false_reg->umax_value = min(false_reg->umax_value, val); false_reg->umax_value = min(false_reg->umax_value, val);
true_reg->umin_value = max(true_reg->umin_value, val + 1); true_reg->umin_value = max(true_reg->umin_value, val + 1);
@ -3944,6 +4028,13 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg,
*/ */
__mark_reg_known(false_reg, val); __mark_reg_known(false_reg, val);
break; break;
case BPF_JSET:
false_reg->var_off = tnum_and(false_reg->var_off,
tnum_const(~val));
if (is_power_of_2(val))
true_reg->var_off = tnum_or(true_reg->var_off,
tnum_const(val));
break;
case BPF_JGT: case BPF_JGT:
true_reg->umax_value = min(true_reg->umax_value, val - 1); true_reg->umax_value = min(true_reg->umax_value, val - 1);
false_reg->umin_value = max(false_reg->umin_value, val); false_reg->umin_value = max(false_reg->umin_value, val);
@ -4561,6 +4652,7 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env)
return 0; return 0;
if (w < 0 || w >= env->prog->len) { if (w < 0 || w >= env->prog->len) {
verbose_linfo(env, t, "%d: ", t);
verbose(env, "jump out of range from insn %d to %d\n", t, w); verbose(env, "jump out of range from insn %d to %d\n", t, w);
return -EINVAL; return -EINVAL;
} }
@ -4578,6 +4670,8 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env)
insn_stack[cur_stack++] = w; insn_stack[cur_stack++] = w;
return 1; return 1;
} else if ((insn_state[w] & 0xF0) == DISCOVERED) { } else if ((insn_state[w] & 0xF0) == DISCOVERED) {
verbose_linfo(env, t, "%d: ", t);
verbose_linfo(env, w, "%d: ", w);
verbose(env, "back-edge from insn %d to %d\n", t, w); verbose(env, "back-edge from insn %d to %d\n", t, w);
return -EINVAL; return -EINVAL;
} else if (insn_state[w] == EXPLORED) { } else if (insn_state[w] == EXPLORED) {
@ -4600,10 +4694,6 @@ static int check_cfg(struct bpf_verifier_env *env)
int ret = 0; int ret = 0;
int i, t; int i, t;
ret = check_subprogs(env);
if (ret < 0)
return ret;
insn_state = kcalloc(insn_cnt, sizeof(int), GFP_KERNEL); insn_state = kcalloc(insn_cnt, sizeof(int), GFP_KERNEL);
if (!insn_state) if (!insn_state)
return -ENOMEM; return -ENOMEM;
@ -4910,8 +5000,16 @@ static int check_btf_line(struct bpf_verifier_env *env,
goto err_free; goto err_free;
} }
if (!btf_name_offset_valid(btf, linfo[i].line_off) || if (!prog->insnsi[linfo[i].insn_off].code) {
!btf_name_offset_valid(btf, linfo[i].file_name_off)) { verbose(env,
"Invalid insn code at line_info[%u].insn_off\n",
i);
err = -EINVAL;
goto err_free;
}
if (!btf_name_by_offset(btf, linfo[i].line_off) ||
!btf_name_by_offset(btf, linfo[i].file_name_off)) {
verbose(env, "Invalid line_info[%u].line_off or .file_name_off\n", i); verbose(env, "Invalid line_info[%u].line_off or .file_name_off\n", i);
err = -EINVAL; err = -EINVAL;
goto err_free; goto err_free;
@ -5021,6 +5119,102 @@ static bool check_ids(u32 old_id, u32 cur_id, struct idpair *idmap)
return false; return false;
} }
static void clean_func_state(struct bpf_verifier_env *env,
struct bpf_func_state *st)
{
enum bpf_reg_liveness live;
int i, j;
for (i = 0; i < BPF_REG_FP; i++) {
live = st->regs[i].live;
/* liveness must not touch this register anymore */
st->regs[i].live |= REG_LIVE_DONE;
if (!(live & REG_LIVE_READ))
/* since the register is unused, clear its state
* to make further comparison simpler
*/
__mark_reg_not_init(&st->regs[i]);
}
for (i = 0; i < st->allocated_stack / BPF_REG_SIZE; i++) {
live = st->stack[i].spilled_ptr.live;
/* liveness must not touch this stack slot anymore */
st->stack[i].spilled_ptr.live |= REG_LIVE_DONE;
if (!(live & REG_LIVE_READ)) {
__mark_reg_not_init(&st->stack[i].spilled_ptr);
for (j = 0; j < BPF_REG_SIZE; j++)
st->stack[i].slot_type[j] = STACK_INVALID;
}
}
}
static void clean_verifier_state(struct bpf_verifier_env *env,
struct bpf_verifier_state *st)
{
int i;
if (st->frame[0]->regs[0].live & REG_LIVE_DONE)
/* all regs in this state in all frames were already marked */
return;
for (i = 0; i <= st->curframe; i++)
clean_func_state(env, st->frame[i]);
}
/* the parentage chains form a tree.
* the verifier states are added to state lists at given insn and
* pushed into state stack for future exploration.
* when the verifier reaches bpf_exit insn some of the verifer states
* stored in the state lists have their final liveness state already,
* but a lot of states will get revised from liveness point of view when
* the verifier explores other branches.
* Example:
* 1: r0 = 1
* 2: if r1 == 100 goto pc+1
* 3: r0 = 2
* 4: exit
* when the verifier reaches exit insn the register r0 in the state list of
* insn 2 will be seen as !REG_LIVE_READ. Then the verifier pops the other_branch
* of insn 2 and goes exploring further. At the insn 4 it will walk the
* parentage chain from insn 4 into insn 2 and will mark r0 as REG_LIVE_READ.
*
* Since the verifier pushes the branch states as it sees them while exploring
* the program the condition of walking the branch instruction for the second
* time means that all states below this branch were already explored and
* their final liveness markes are already propagated.
* Hence when the verifier completes the search of state list in is_state_visited()
* we can call this clean_live_states() function to mark all liveness states
* as REG_LIVE_DONE to indicate that 'parent' pointers of 'struct bpf_reg_state'
* will not be used.
* This function also clears the registers and stack for states that !READ
* to simplify state merging.
*
* Important note here that walking the same branch instruction in the callee
* doesn't meant that the states are DONE. The verifier has to compare
* the callsites
*/
static void clean_live_states(struct bpf_verifier_env *env, int insn,
struct bpf_verifier_state *cur)
{
struct bpf_verifier_state_list *sl;
int i;
sl = env->explored_states[insn];
if (!sl)
return;
while (sl != STATE_LIST_MARK) {
if (sl->state.curframe != cur->curframe)
goto next;
for (i = 0; i <= cur->curframe; i++)
if (sl->state.frame[i]->callsite != cur->frame[i]->callsite)
goto next;
clean_verifier_state(env, &sl->state);
next:
sl = sl->next;
}
}
/* Returns true if (rold safe implies rcur safe) */ /* Returns true if (rold safe implies rcur safe) */
static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
struct idpair *idmap) struct idpair *idmap)
@ -5134,12 +5328,6 @@ static bool stacksafe(struct bpf_func_state *old,
{ {
int i, spi; int i, spi;
/* if explored stack has more populated slots than current stack
* such stacks are not equivalent
*/
if (old->allocated_stack > cur->allocated_stack)
return false;
/* walk slots of the explored stack and ignore any additional /* walk slots of the explored stack and ignore any additional
* slots in the current stack, since explored(safe) state * slots in the current stack, since explored(safe) state
* didn't use them * didn't use them
@ -5147,12 +5335,21 @@ static bool stacksafe(struct bpf_func_state *old,
for (i = 0; i < old->allocated_stack; i++) { for (i = 0; i < old->allocated_stack; i++) {
spi = i / BPF_REG_SIZE; spi = i / BPF_REG_SIZE;
if (!(old->stack[spi].spilled_ptr.live & REG_LIVE_READ)) if (!(old->stack[spi].spilled_ptr.live & REG_LIVE_READ)) {
i += BPF_REG_SIZE - 1;
/* explored state didn't use this */ /* explored state didn't use this */
continue; continue;
}
if (old->stack[spi].slot_type[i % BPF_REG_SIZE] == STACK_INVALID) if (old->stack[spi].slot_type[i % BPF_REG_SIZE] == STACK_INVALID)
continue; continue;
/* explored stack has more populated slots than current stack
* and these slots were used
*/
if (i >= cur->allocated_stack)
return false;
/* if old state was safe with misc data in the stack /* if old state was safe with misc data in the stack
* it will be safe with zero-initialized stack. * it will be safe with zero-initialized stack.
* The opposite is not true * The opposite is not true
@ -5336,6 +5533,8 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
*/ */
return 0; return 0;
clean_live_states(env, insn_idx, cur);
while (sl != STATE_LIST_MARK) { while (sl != STATE_LIST_MARK) {
if (states_equal(env, &sl->state, cur)) { if (states_equal(env, &sl->state, cur)) {
/* reached equivalent register/stack state, /* reached equivalent register/stack state,
@ -5455,6 +5654,8 @@ static int do_check(struct bpf_verifier_env *env)
int insn_processed = 0; int insn_processed = 0;
bool do_print_state = false; bool do_print_state = false;
env->prev_linfo = NULL;
state = kzalloc(sizeof(struct bpf_verifier_state), GFP_KERNEL); state = kzalloc(sizeof(struct bpf_verifier_state), GFP_KERNEL);
if (!state) if (!state)
return -ENOMEM; return -ENOMEM;
@ -5528,6 +5729,7 @@ static int do_check(struct bpf_verifier_env *env)
.private_data = env, .private_data = env,
}; };
verbose_linfo(env, insn_idx, "; ");
verbose(env, "%d: ", insn_idx); verbose(env, "%d: ", insn_idx);
print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); print_bpf_insn(&cbs, insn, env->allow_ptr_leaks);
} }
@ -6762,7 +6964,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);
ret = check_cfg(env); ret = check_subprogs(env);
if (ret < 0) if (ret < 0)
goto skip_full_check; goto skip_full_check;
@ -6770,6 +6972,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
if (ret < 0) if (ret < 0)
goto skip_full_check; goto skip_full_check;
ret = check_cfg(env);
if (ret < 0)
goto skip_full_check;
ret = do_check(env); ret = do_check(env);
if (env->cur_state) { if (env->cur_state) {
free_verifier_state(env->cur_state, true); free_verifier_state(env->cur_state, true);
@ -6783,12 +6989,13 @@ skip_full_check:
while (!pop_stack(env, NULL, NULL)); while (!pop_stack(env, NULL, NULL));
free_states(env); free_states(env);
if (ret == 0)
sanitize_dead_code(env);
if (ret == 0) if (ret == 0)
ret = check_max_stack_depth(env); ret = check_max_stack_depth(env);
/* instruction rewrites happen after this point */
if (ret == 0)
sanitize_dead_code(env);
if (ret == 0) if (ret == 0)
/* program is valid, convert *(u32*)(ctx + off) accesses */ /* program is valid, convert *(u32*)(ctx + off) accesses */
ret = convert_ctx_accesses(env); ret = convert_ctx_accesses(env);

Просмотреть файл

@ -3093,6 +3093,11 @@ static int find_module_sections(struct module *mod, struct load_info *info)
sizeof(*mod->tracepoints_ptrs), sizeof(*mod->tracepoints_ptrs),
&mod->num_tracepoints); &mod->num_tracepoints);
#endif #endif
#ifdef CONFIG_BPF_EVENTS
mod->bpf_raw_events = section_objs(info, "__bpf_raw_tp_map",
sizeof(*mod->bpf_raw_events),
&mod->num_bpf_raw_events);
#endif
#ifdef HAVE_JUMP_LABEL #ifdef HAVE_JUMP_LABEL
mod->jump_entries = section_objs(info, "__jump_table", mod->jump_entries = section_objs(info, "__jump_table",
sizeof(*mod->jump_entries), sizeof(*mod->jump_entries),

Просмотреть файл

@ -17,6 +17,43 @@
#include "trace_probe.h" #include "trace_probe.h"
#include "trace.h" #include "trace.h"
#ifdef CONFIG_MODULES
struct bpf_trace_module {
struct module *module;
struct list_head list;
};
static LIST_HEAD(bpf_trace_modules);
static DEFINE_MUTEX(bpf_module_mutex);
static struct bpf_raw_event_map *bpf_get_raw_tracepoint_module(const char *name)
{
struct bpf_raw_event_map *btp, *ret = NULL;
struct bpf_trace_module *btm;
unsigned int i;
mutex_lock(&bpf_module_mutex);
list_for_each_entry(btm, &bpf_trace_modules, list) {
for (i = 0; i < btm->module->num_bpf_raw_events; ++i) {
btp = &btm->module->bpf_raw_events[i];
if (!strcmp(btp->tp->name, name)) {
if (try_module_get(btm->module))
ret = btp;
goto out;
}
}
}
out:
mutex_unlock(&bpf_module_mutex);
return ret;
}
#else
static struct bpf_raw_event_map *bpf_get_raw_tracepoint_module(const char *name)
{
return NULL;
}
#endif /* CONFIG_MODULES */
u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
u64 bpf_get_stack(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); u64 bpf_get_stack(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
@ -1076,7 +1113,7 @@ int perf_event_query_prog_array(struct perf_event *event, void __user *info)
extern struct bpf_raw_event_map __start__bpf_raw_tp[]; extern struct bpf_raw_event_map __start__bpf_raw_tp[];
extern struct bpf_raw_event_map __stop__bpf_raw_tp[]; extern struct bpf_raw_event_map __stop__bpf_raw_tp[];
struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name) struct bpf_raw_event_map *bpf_get_raw_tracepoint(const char *name)
{ {
struct bpf_raw_event_map *btp = __start__bpf_raw_tp; struct bpf_raw_event_map *btp = __start__bpf_raw_tp;
@ -1084,7 +1121,16 @@ struct bpf_raw_event_map *bpf_find_raw_tracepoint(const char *name)
if (!strcmp(btp->tp->name, name)) if (!strcmp(btp->tp->name, name))
return btp; return btp;
} }
return NULL;
return bpf_get_raw_tracepoint_module(name);
}
void bpf_put_raw_tracepoint(struct bpf_raw_event_map *btp)
{
struct module *mod = __module_address((unsigned long)btp);
if (mod)
module_put(mod);
} }
static __always_inline static __always_inline
@ -1222,3 +1268,52 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
return err; return err;
} }
#ifdef CONFIG_MODULES
int bpf_event_notify(struct notifier_block *nb, unsigned long op, void *module)
{
struct bpf_trace_module *btm, *tmp;
struct module *mod = module;
if (mod->num_bpf_raw_events == 0 ||
(op != MODULE_STATE_COMING && op != MODULE_STATE_GOING))
return 0;
mutex_lock(&bpf_module_mutex);
switch (op) {
case MODULE_STATE_COMING:
btm = kzalloc(sizeof(*btm), GFP_KERNEL);
if (btm) {
btm->module = module;
list_add(&btm->list, &bpf_trace_modules);
}
break;
case MODULE_STATE_GOING:
list_for_each_entry_safe(btm, tmp, &bpf_trace_modules, list) {
if (btm->module == module) {
list_del(&btm->list);
kfree(btm);
break;
}
}
break;
}
mutex_unlock(&bpf_module_mutex);
return 0;
}
static struct notifier_block bpf_module_nb = {
.notifier_call = bpf_event_notify,
};
int __init bpf_event_init(void)
{
register_module_notifier(&bpf_module_nb);
return 0;
}
fs_initcall(bpf_event_init);
#endif /* CONFIG_MODULES */

Просмотреть файл

@ -6313,6 +6313,9 @@ static bool sk_msg_is_valid_access(int off, int size,
if (type == BPF_WRITE) if (type == BPF_WRITE)
return false; return false;
if (off % size != 0)
return false;
switch (off) { switch (off) {
case offsetof(struct sk_msg_md, data): case offsetof(struct sk_msg_md, data):
info->reg_type = PTR_TO_PACKET; info->reg_type = PTR_TO_PACKET;
@ -6324,16 +6327,20 @@ static bool sk_msg_is_valid_access(int off, int size,
if (size != sizeof(__u64)) if (size != sizeof(__u64))
return false; return false;
break; break;
default: case bpf_ctx_range(struct sk_msg_md, family):
case bpf_ctx_range(struct sk_msg_md, remote_ip4):
case bpf_ctx_range(struct sk_msg_md, local_ip4):
case bpf_ctx_range_till(struct sk_msg_md, remote_ip6[0], remote_ip6[3]):
case bpf_ctx_range_till(struct sk_msg_md, local_ip6[0], local_ip6[3]):
case bpf_ctx_range(struct sk_msg_md, remote_port):
case bpf_ctx_range(struct sk_msg_md, local_port):
case bpf_ctx_range(struct sk_msg_md, size):
if (size != sizeof(__u32)) if (size != sizeof(__u32))
return false; return false;
break;
default:
return false;
} }
if (off < 0 || off >= sizeof(struct sk_msg_md))
return false;
if (off % size != 0)
return false;
return true; return true;
} }
@ -7418,6 +7425,9 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type,
int off; int off;
#endif #endif
/* convert ctx uses the fact sg element is first in struct */
BUILD_BUG_ON(offsetof(struct sk_msg, sg) != 0);
switch (si->off) { switch (si->off) {
case offsetof(struct sk_msg_md, data): case offsetof(struct sk_msg_md, data):
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_msg, data), *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_msg, data),
@ -7530,6 +7540,12 @@ static u32 sk_msg_convert_ctx_access(enum bpf_access_type type,
*insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg, *insn++ = BPF_LDX_MEM(BPF_H, si->dst_reg, si->dst_reg,
offsetof(struct sock_common, skc_num)); offsetof(struct sock_common, skc_num));
break; break;
case offsetof(struct sk_msg_md, size):
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_msg_sg, size),
si->dst_reg, si->src_reg,
offsetof(struct sk_msg_sg, size));
break;
} }
return insn - insn_buf; return insn - insn_buf;

Просмотреть файл

@ -403,7 +403,7 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb)
msg->skb = skb; msg->skb = skb;
sk_psock_queue_msg(psock, msg); sk_psock_queue_msg(psock, msg);
sk->sk_data_ready(sk); sk_psock_data_ready(sk, psock);
return copied; return copied;
} }
@ -572,6 +572,7 @@ void sk_psock_drop(struct sock *sk, struct sk_psock *psock)
{ {
rcu_assign_sk_user_data(sk, NULL); rcu_assign_sk_user_data(sk, NULL);
sk_psock_cork_free(psock); sk_psock_cork_free(psock);
sk_psock_zap_ingress(psock);
sk_psock_restore_proto(sk, psock); sk_psock_restore_proto(sk, psock);
write_lock_bh(&sk->sk_callback_lock); write_lock_bh(&sk->sk_callback_lock);
@ -669,6 +670,22 @@ static void sk_psock_verdict_apply(struct sk_psock *psock,
bool ingress; bool ingress;
switch (verdict) { switch (verdict) {
case __SK_PASS:
sk_other = psock->sk;
if (sock_flag(sk_other, SOCK_DEAD) ||
!sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) {
goto out_free;
}
if (atomic_read(&sk_other->sk_rmem_alloc) <=
sk_other->sk_rcvbuf) {
struct tcp_skb_cb *tcp = TCP_SKB_CB(skb);
tcp->bpf.flags |= BPF_F_INGRESS;
skb_queue_tail(&psock->ingress_skb, skb);
schedule_work(&psock->work);
break;
}
goto out_free;
case __SK_REDIRECT: case __SK_REDIRECT:
sk_other = tcp_skb_bpf_redirect_fetch(skb); sk_other = tcp_skb_bpf_redirect_fetch(skb);
if (unlikely(!sk_other)) if (unlikely(!sk_other))
@ -735,7 +752,7 @@ static int sk_psock_strp_parse(struct strparser *strp, struct sk_buff *skb)
} }
/* Called with socket lock held. */ /* Called with socket lock held. */
static void sk_psock_data_ready(struct sock *sk) static void sk_psock_strp_data_ready(struct sock *sk)
{ {
struct sk_psock *psock; struct sk_psock *psock;
@ -783,7 +800,7 @@ void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock)
return; return;
parser->saved_data_ready = sk->sk_data_ready; parser->saved_data_ready = sk->sk_data_ready;
sk->sk_data_ready = sk_psock_data_ready; sk->sk_data_ready = sk_psock_strp_data_ready;
sk->sk_write_space = sk_psock_write_space; sk->sk_write_space = sk_psock_write_space;
parser->enabled = true; parser->enabled = true;
} }

Просмотреть файл

@ -8,6 +8,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <net/inet_common.h> #include <net/inet_common.h>
#include <net/tls.h>
static bool tcp_bpf_stream_read(const struct sock *sk) static bool tcp_bpf_stream_read(const struct sock *sk)
{ {
@ -198,7 +199,7 @@ static int bpf_tcp_ingress(struct sock *sk, struct sk_psock *psock,
msg->sg.start = i; msg->sg.start = i;
msg->sg.size -= apply_bytes; msg->sg.size -= apply_bytes;
sk_psock_queue_msg(psock, tmp); sk_psock_queue_msg(psock, tmp);
sk->sk_data_ready(sk); sk_psock_data_ready(sk, psock);
} else { } else {
sk_msg_free(sk, tmp); sk_msg_free(sk, tmp);
kfree(tmp); kfree(tmp);
@ -218,6 +219,8 @@ static int tcp_bpf_push(struct sock *sk, struct sk_msg *msg, u32 apply_bytes,
u32 off; u32 off;
while (1) { while (1) {
bool has_tx_ulp;
sge = sk_msg_elem(msg, msg->sg.start); sge = sk_msg_elem(msg, msg->sg.start);
size = (apply && apply_bytes < sge->length) ? size = (apply && apply_bytes < sge->length) ?
apply_bytes : sge->length; apply_bytes : sge->length;
@ -226,7 +229,15 @@ static int tcp_bpf_push(struct sock *sk, struct sk_msg *msg, u32 apply_bytes,
tcp_rate_check_app_limited(sk); tcp_rate_check_app_limited(sk);
retry: retry:
ret = do_tcp_sendpages(sk, page, off, size, flags); has_tx_ulp = tls_sw_has_ctx_tx(sk);
if (has_tx_ulp) {
flags |= MSG_SENDPAGE_NOPOLICY;
ret = kernel_sendpage_locked(sk,
page, off, size, flags);
} else {
ret = do_tcp_sendpages(sk, page, off, size, flags);
}
if (ret <= 0) if (ret <= 0)
return ret; return ret;
if (apply) if (apply)

Просмотреть файл

@ -55,6 +55,8 @@ enum {
static struct proto *saved_tcpv6_prot; static struct proto *saved_tcpv6_prot;
static DEFINE_MUTEX(tcpv6_prot_mutex); static DEFINE_MUTEX(tcpv6_prot_mutex);
static struct proto *saved_tcpv4_prot;
static DEFINE_MUTEX(tcpv4_prot_mutex);
static LIST_HEAD(device_list); static LIST_HEAD(device_list);
static DEFINE_SPINLOCK(device_spinlock); static DEFINE_SPINLOCK(device_spinlock);
static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG]; static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG];
@ -700,6 +702,16 @@ static int tls_init(struct sock *sk)
mutex_unlock(&tcpv6_prot_mutex); mutex_unlock(&tcpv6_prot_mutex);
} }
if (ip_ver == TLSV4 &&
unlikely(sk->sk_prot != smp_load_acquire(&saved_tcpv4_prot))) {
mutex_lock(&tcpv4_prot_mutex);
if (likely(sk->sk_prot != saved_tcpv4_prot)) {
build_protos(tls_prots[TLSV4], sk->sk_prot);
smp_store_release(&saved_tcpv4_prot, sk->sk_prot);
}
mutex_unlock(&tcpv4_prot_mutex);
}
ctx->tx_conf = TLS_BASE; ctx->tx_conf = TLS_BASE;
ctx->rx_conf = TLS_BASE; ctx->rx_conf = TLS_BASE;
update_sk_prot(sk, ctx); update_sk_prot(sk, ctx);
@ -731,8 +743,6 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
static int __init tls_register(void) static int __init tls_register(void)
{ {
build_protos(tls_prots[TLSV4], &tcp_prot);
tls_sw_proto_ops = inet_stream_ops; tls_sw_proto_ops = inet_stream_ops;
tls_sw_proto_ops.splice_read = tls_sw_splice_read; tls_sw_proto_ops.splice_read = tls_sw_splice_read;

Просмотреть файл

@ -686,12 +686,13 @@ static int bpf_exec_tx_verdict(struct sk_msg *msg, struct sock *sk,
struct sk_psock *psock; struct sk_psock *psock;
struct sock *sk_redir; struct sock *sk_redir;
struct tls_rec *rec; struct tls_rec *rec;
bool enospc, policy;
int err = 0, send; int err = 0, send;
u32 delta = 0; u32 delta = 0;
bool enospc;
policy = !(flags & MSG_SENDPAGE_NOPOLICY);
psock = sk_psock_get(sk); psock = sk_psock_get(sk);
if (!psock) if (!psock || !policy)
return tls_push_record(sk, flags, record_type); return tls_push_record(sk, flags, record_type);
more_data: more_data:
enospc = sk_msg_full(msg); enospc = sk_msg_full(msg);
@ -1017,8 +1018,8 @@ send_end:
return copied ? copied : ret; return copied ? copied : ret;
} }
int tls_sw_sendpage(struct sock *sk, struct page *page, int tls_sw_do_sendpage(struct sock *sk, struct page *page,
int offset, size_t size, int flags) int offset, size_t size, int flags)
{ {
long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_context *tls_ctx = tls_get_ctx(sk);
@ -1033,15 +1034,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page,
int ret = 0; int ret = 0;
bool eor; bool eor;
if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL |
MSG_SENDPAGE_NOTLAST))
return -ENOTSUPP;
/* No MSG_EOR from splice, only look at MSG_MORE */
eor = !(flags & (MSG_MORE | MSG_SENDPAGE_NOTLAST)); eor = !(flags & (MSG_MORE | MSG_SENDPAGE_NOTLAST));
lock_sock(sk);
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
/* Wait till there is any pending write on socket */ /* Wait till there is any pending write on socket */
@ -1145,10 +1138,34 @@ wait_for_memory:
} }
sendpage_end: sendpage_end:
ret = sk_stream_error(sk, flags, ret); ret = sk_stream_error(sk, flags, ret);
release_sock(sk);
return copied ? copied : ret; return copied ? copied : ret;
} }
int tls_sw_sendpage_locked(struct sock *sk, struct page *page,
int offset, size_t size, int flags)
{
if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL |
MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY))
return -ENOTSUPP;
return tls_sw_do_sendpage(sk, page, offset, size, flags);
}
int tls_sw_sendpage(struct sock *sk, struct page *page,
int offset, size_t size, int flags)
{
int ret;
if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL |
MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY))
return -ENOTSUPP;
lock_sock(sk);
ret = tls_sw_do_sendpage(sk, page, offset, size, flags);
release_sock(sk);
return ret;
}
static struct sk_buff *tls_wait_data(struct sock *sk, struct sk_psock *psock, static struct sk_buff *tls_wait_data(struct sock *sk, struct sk_psock *psock,
int flags, long timeo, int *err) int flags, long timeo, int *err)
{ {

Просмотреть файл

@ -366,6 +366,7 @@ static int xsk_release(struct socket *sock)
xskq_destroy(xs->rx); xskq_destroy(xs->rx);
xskq_destroy(xs->tx); xskq_destroy(xs->tx);
xdp_put_umem(xs->umem);
sock_orphan(sk); sock_orphan(sk);
sock->sk = NULL; sock->sk = NULL;
@ -713,18 +714,6 @@ static const struct proto_ops xsk_proto_ops = {
.sendpage = sock_no_sendpage, .sendpage = sock_no_sendpage,
}; };
static void xsk_destruct(struct sock *sk)
{
struct xdp_sock *xs = xdp_sk(sk);
if (!sock_flag(sk, SOCK_DEAD))
return;
xdp_put_umem(xs->umem);
sk_refcnt_debug_dec(sk);
}
static int xsk_create(struct net *net, struct socket *sock, int protocol, static int xsk_create(struct net *net, struct socket *sock, int protocol,
int kern) int kern)
{ {
@ -751,9 +740,6 @@ static int xsk_create(struct net *net, struct socket *sock, int protocol,
sk->sk_family = PF_XDP; sk->sk_family = PF_XDP;
sk->sk_destruct = xsk_destruct;
sk_refcnt_debug_inc(sk);
sock_set_flag(sk, SOCK_RCU_FREE); sock_set_flag(sk, SOCK_RCU_FREE);
xs = xdp_sk(sk); xs = xdp_sk(sk);

Просмотреть файл

@ -128,6 +128,10 @@ OPTIONS
-f, --bpffs -f, --bpffs
Show file names of pinned maps. Show file names of pinned maps.
-n, --nomount
Do not automatically attempt to mount any virtual file system
(such as tracefs or BPF virtual file system) when necessary.
EXAMPLES EXAMPLES
======== ========
**# bpftool map show** **# bpftool map show**
@ -170,6 +174,61 @@ The following three commands are equivalent:
| **# bpftool map pin id 10 /sys/fs/bpf/map** | **# bpftool map pin id 10 /sys/fs/bpf/map**
| **# bpftool map del pinned /sys/fs/bpf/map key 13 00 07 00** | **# bpftool map del pinned /sys/fs/bpf/map key 13 00 07 00**
Note that map update can also be used in order to change the program references
hold by a program array map. This can be used, for example, to change the
programs used for tail-call jumps at runtime, without having to reload the
entry-point program. Below is an example for this use case: we load a program
defining a prog array map, and with a main function that contains a tail call
to other programs that can be used either to "process" packets or to "debug"
processing. Note that the prog array map MUST be pinned into the BPF virtual
file system for the map update to work successfully, as kernel flushes prog
array maps when they have no more references from user space (and the update
would be lost as soon as bpftool exits).
|
| **# bpftool prog loadall tail_calls.o /sys/fs/bpf/foo type xdp**
| **# bpftool prog --bpffs**
::
545: xdp name main_func tag 674b4b5597193dc3 gpl
loaded_at 2018-12-12T15:02:58+0000 uid 0
xlated 240B jited 257B memlock 4096B map_ids 294
pinned /sys/fs/bpf/foo/xdp
546: xdp name bpf_func_process tag e369a529024751fc gpl
loaded_at 2018-12-12T15:02:58+0000 uid 0
xlated 200B jited 164B memlock 4096B
pinned /sys/fs/bpf/foo/process
547: xdp name bpf_func_debug tag 0b597868bc7f0976 gpl
loaded_at 2018-12-12T15:02:58+0000 uid 0
xlated 200B jited 164B memlock 4096B
pinned /sys/fs/bpf/foo/debug
**# bpftool map**
::
294: prog_array name jmp_table flags 0x0
key 4B value 4B max_entries 1 memlock 4096B
owner_prog_type xdp owner jited
|
| **# bpftool map pin id 294 /sys/fs/bpf/bar**
| **# bpftool map dump pinned /sys/fs/bpf/bar**
::
Found 0 elements
|
| **# bpftool map update pinned /sys/fs/bpf/bar key 0 0 0 0 value pinned /sys/fs/bpf/foo/debug**
| **# bpftool map dump pinned /sys/fs/bpf/bar**
::
key: 00 00 00 00 value: 22 02 00 00
Found 1 element
SEE ALSO SEE ALSO
======== ========
**bpf**\ (2), **bpf**\ (2),

Просмотреть файл

@ -158,83 +158,98 @@ OPTIONS
When showing BPF programs, show file names of pinned When showing BPF programs, show file names of pinned
programs. programs.
-m, --mapcompat
Allow loading maps with unknown map definitions.
-n, --nomount
Do not automatically attempt to mount any virtual file system
(such as tracefs or BPF virtual file system) when necessary.
EXAMPLES EXAMPLES
======== ========
**# bpftool prog show** **# bpftool prog show**
:: ::
10: xdp name some_prog tag 005a3d2123620c8b gpl 10: xdp name some_prog tag 005a3d2123620c8b gpl
loaded_at Sep 29/20:11 uid 0 loaded_at 2017-09-29T20:11:00+0000 uid 0
xlated 528B jited 370B memlock 4096B map_ids 10 xlated 528B jited 370B memlock 4096B map_ids 10
**# bpftool --json --pretty prog show** **# bpftool --json --pretty prog show**
:: ::
{ [{
"programs": [{ "id": 10,
"id": 10, "type": "xdp",
"type": "xdp", "tag": "005a3d2123620c8b",
"tag": "005a3d2123620c8b", "gpl_compatible": true,
"gpl_compatible": true, "loaded_at": 1506715860,
"loaded_at": "Sep 29/20:11", "uid": 0,
"uid": 0, "bytes_xlated": 528,
"bytes_xlated": 528, "jited": true,
"jited": true, "bytes_jited": 370,
"bytes_jited": 370, "bytes_memlock": 4096,
"bytes_memlock": 4096, "map_ids": [10
"map_ids": [10 ]
] }
} ]
]
}
| |
| **# bpftool prog dump xlated id 10 file /tmp/t** | **# bpftool prog dump xlated id 10 file /tmp/t**
| **# ls -l /tmp/t** | **# ls -l /tmp/t**
| -rw------- 1 root root 560 Jul 22 01:42 /tmp/t
**# bpftool prog dum jited tag 005a3d2123620c8b**
:: ::
push %rbp -rw------- 1 root root 560 Jul 22 01:42 /tmp/t
mov %rsp,%rbp
sub $0x228,%rsp **# bpftool prog dump jited tag 005a3d2123620c8b**
sub $0x28,%rbp
mov %rbx,0x0(%rbp) ::
0: push %rbp
1: mov %rsp,%rbp
2: sub $0x228,%rsp
3: sub $0x28,%rbp
4: mov %rbx,0x0(%rbp)
| |
| **# mount -t bpf none /sys/fs/bpf/** | **# mount -t bpf none /sys/fs/bpf/**
| **# bpftool prog pin id 10 /sys/fs/bpf/prog** | **# bpftool prog pin id 10 /sys/fs/bpf/prog**
| **# bpftool prog load ./my_prog.o /sys/fs/bpf/prog2** | **# bpftool prog load ./my_prog.o /sys/fs/bpf/prog2**
| **# ls -l /sys/fs/bpf/** | **# ls -l /sys/fs/bpf/**
| -rw------- 1 root root 0 Jul 22 01:43 prog
| -rw------- 1 root root 0 Jul 22 01:44 prog2
**# bpftool prog dum jited pinned /sys/fs/bpf/prog opcodes**
:: ::
push %rbp -rw------- 1 root root 0 Jul 22 01:43 prog
55 -rw------- 1 root root 0 Jul 22 01:44 prog2
mov %rsp,%rbp
48 89 e5 **# bpftool prog dump jited pinned /sys/fs/bpf/prog opcodes**
sub $0x228,%rsp
48 81 ec 28 02 00 00 ::
sub $0x28,%rbp
48 83 ed 28 0: push %rbp
mov %rbx,0x0(%rbp) 55
48 89 5d 00 1: mov %rsp,%rbp
48 89 e5
4: sub $0x228,%rsp
48 81 ec 28 02 00 00
b: sub $0x28,%rbp
48 83 ed 28
f: mov %rbx,0x0(%rbp)
48 89 5d 00
| |
| **# bpftool prog load xdp1_kern.o /sys/fs/bpf/xdp1 type xdp map name rxcnt id 7** | **# bpftool prog load xdp1_kern.o /sys/fs/bpf/xdp1 type xdp map name rxcnt id 7**
| **# bpftool prog show pinned /sys/fs/bpf/xdp1** | **# bpftool prog show pinned /sys/fs/bpf/xdp1**
| 9: xdp name xdp_prog1 tag 539ec6ce11b52f98 gpl
| loaded_at 2018-06-25T16:17:31-0700 uid 0 ::
| xlated 488B jited 336B memlock 4096B map_ids 7
| **# rm /sys/fs/bpf/xdp1** 9: xdp name xdp_prog1 tag 539ec6ce11b52f98 gpl
| loaded_at 2018-06-25T16:17:31-0700 uid 0
xlated 488B jited 336B memlock 4096B map_ids 7
**# rm /sys/fs/bpf/xdp1**
SEE ALSO SEE ALSO
======== ========

Просмотреть файл

@ -60,6 +60,10 @@ OPTIONS
-m, --mapcompat -m, --mapcompat
Allow loading maps with unknown map definitions. Allow loading maps with unknown map definitions.
-n, --nomount
Do not automatically attempt to mount any virtual file system
(such as tracefs or BPF virtual file system) when necessary.
SEE ALSO SEE ALSO
======== ========

Просмотреть файл

@ -35,8 +35,6 @@ $(LIBBPF)-clean:
prefix ?= /usr/local prefix ?= /usr/local
bash_compdir ?= /usr/share/bash-completion/completions bash_compdir ?= /usr/share/bash-completion/completions
CC = gcc
CFLAGS += -O2 CFLAGS += -O2
CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wshadow -Wno-missing-field-initializers CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wshadow -Wno-missing-field-initializers
CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \ CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \

Просмотреть файл

@ -1,37 +1,8 @@
# bpftool(8) bash completion -*- shell-script -*- # bpftool(8) bash completion -*- shell-script -*-
# #
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2017-2018 Netronome Systems, Inc. # Copyright (C) 2017-2018 Netronome Systems, Inc.
# #
# This software is dual licensed under the GNU General License
# Version 2, June 1991 as shown in the file COPYING in the top-level
# directory of this source tree or the BSD 2-Clause License provided
# below. You have the option to license this software under the
# complete terms of either license.
#
# The BSD 2-Clause License:
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Author: Quentin Monnet <quentin.monnet@netronome.com> # Author: Quentin Monnet <quentin.monnet@netronome.com>
# Takes a list of words in argument; each one of them is added to COMPREPLY if # Takes a list of words in argument; each one of them is added to COMPREPLY if

Просмотреть файл

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright (c) 2018 Facebook */ /* Copyright (c) 2018 Facebook */
#include <ctype.h> #include <ctype.h>
@ -73,20 +73,17 @@ static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id,
return ret; return ret;
} }
static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset, static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset,
const void *data, json_writer_t *jw, const void *data, json_writer_t *jw,
bool is_plain_text) bool is_plain_text)
{ {
int left_shift_bits, right_shift_bits; int left_shift_bits, right_shift_bits;
int nr_bits = BTF_INT_BITS(int_type);
int total_bits_offset;
int bytes_to_copy; int bytes_to_copy;
int bits_to_copy; int bits_to_copy;
__u64 print_num; __u64 print_num;
total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type); data += BITS_ROUNDDOWN_BYTES(bit_offset);
data += BITS_ROUNDDOWN_BYTES(total_bits_offset); bit_offset = BITS_PER_BYTE_MASKED(bit_offset);
bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
bits_to_copy = bit_offset + nr_bits; bits_to_copy = bit_offset + nr_bits;
bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy); bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
@ -109,6 +106,22 @@ static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
jsonw_printf(jw, "%llu", print_num); jsonw_printf(jw, "%llu", print_num);
} }
static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
const void *data, json_writer_t *jw,
bool is_plain_text)
{
int nr_bits = BTF_INT_BITS(int_type);
int total_bits_offset;
/* bits_offset is at most 7.
* BTF_INT_OFFSET() cannot exceed 64 bits.
*/
total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
btf_dumper_bitfield(nr_bits, total_bits_offset, data, jw,
is_plain_text);
}
static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset, static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset,
const void *data, json_writer_t *jw, const void *data, json_writer_t *jw,
bool is_plain_text) bool is_plain_text)
@ -180,6 +193,7 @@ static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id,
const struct btf_type *t; const struct btf_type *t;
struct btf_member *m; struct btf_member *m;
const void *data_off; const void *data_off;
int kind_flag;
int ret = 0; int ret = 0;
int i, vlen; int i, vlen;
@ -187,18 +201,32 @@ static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id,
if (!t) if (!t)
return -EINVAL; return -EINVAL;
kind_flag = BTF_INFO_KFLAG(t->info);
vlen = BTF_INFO_VLEN(t->info); vlen = BTF_INFO_VLEN(t->info);
jsonw_start_object(d->jw); jsonw_start_object(d->jw);
m = (struct btf_member *)(t + 1); m = (struct btf_member *)(t + 1);
for (i = 0; i < vlen; i++) { for (i = 0; i < vlen; i++) {
data_off = data + BITS_ROUNDDOWN_BYTES(m[i].offset); __u32 bit_offset = m[i].offset;
__u32 bitfield_size = 0;
if (kind_flag) {
bitfield_size = BTF_MEMBER_BITFIELD_SIZE(bit_offset);
bit_offset = BTF_MEMBER_BIT_OFFSET(bit_offset);
}
jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off)); jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off));
ret = btf_dumper_do_type(d, m[i].type, if (bitfield_size) {
BITS_PER_BYTE_MASKED(m[i].offset), btf_dumper_bitfield(bitfield_size, bit_offset,
data_off); data, d->jw, d->is_plain_text);
if (ret) } else {
break; data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset);
ret = btf_dumper_do_type(d, m[i].type,
BITS_PER_BYTE_MASKED(bit_offset),
data_off);
if (ret)
break;
}
} }
jsonw_end_object(d->jw); jsonw_end_object(d->jw);
@ -285,6 +313,7 @@ static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
switch (BTF_INFO_KIND(t->info)) { switch (BTF_INFO_KIND(t->info)) {
case BTF_KIND_INT: case BTF_KIND_INT:
case BTF_KIND_TYPEDEF:
BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off)); BTF_PRINT_ARG("%s ", btf__name_by_offset(btf, t->name_off));
break; break;
case BTF_KIND_STRUCT: case BTF_KIND_STRUCT:
@ -308,10 +337,11 @@ static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
BTF_PRINT_TYPE(t->type); BTF_PRINT_TYPE(t->type);
BTF_PRINT_ARG("* "); BTF_PRINT_ARG("* ");
break; break;
case BTF_KIND_UNKN:
case BTF_KIND_FWD: case BTF_KIND_FWD:
case BTF_KIND_TYPEDEF: BTF_PRINT_ARG("%s %s ",
return -1; BTF_INFO_KFLAG(t->info) ? "union" : "struct",
btf__name_by_offset(btf, t->name_off));
break;
case BTF_KIND_VOLATILE: case BTF_KIND_VOLATILE:
BTF_PRINT_ARG("volatile "); BTF_PRINT_ARG("volatile ");
BTF_PRINT_TYPE(t->type); BTF_PRINT_TYPE(t->type);
@ -335,6 +365,7 @@ static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
if (pos == -1) if (pos == -1)
return -1; return -1;
break; break;
case BTF_KIND_UNKN:
default: default:
return -1; return -1;
} }

Просмотреть файл

@ -1,39 +1,5 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* /* Copyright (C) 2018 Netronome Systems, Inc. */
* Copyright (C) 2018 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/list.h> #include <linux/list.h>
#include <stdlib.h> #include <stdlib.h>

Просмотреть файл

@ -1,39 +1,5 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/* /* Copyright (C) 2018 Netronome Systems, Inc. */
* Copyright (C) 2018 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BPF_TOOL_CFG_H #ifndef __BPF_TOOL_CFG_H
#define __BPF_TOOL_CFG_H #define __BPF_TOOL_CFG_H

Просмотреть файл

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
// Copyright (C) 2017 Facebook // Copyright (C) 2017 Facebook
// Author: Roman Gushchin <guro@fb.com> // Author: Roman Gushchin <guro@fb.com>

Просмотреть файл

@ -1,35 +1,5 @@
/* // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
* Copyright (C) 2017-2018 Netronome Systems, Inc. /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
@ -58,7 +28,7 @@
#define BPF_FS_MAGIC 0xcafe4a11 #define BPF_FS_MAGIC 0xcafe4a11
#endif #endif
void p_err(const char *fmt, ...) void __printf(1, 2) p_err(const char *fmt, ...)
{ {
va_list ap; va_list ap;
@ -76,7 +46,7 @@ void p_err(const char *fmt, ...)
va_end(ap); va_end(ap);
} }
void p_info(const char *fmt, ...) void __printf(1, 2) p_info(const char *fmt, ...)
{ {
va_list ap; va_list ap;
@ -106,7 +76,8 @@ void set_max_rlimit(void)
setrlimit(RLIMIT_MEMLOCK, &rinf); setrlimit(RLIMIT_MEMLOCK, &rinf);
} }
static int mnt_bpffs(const char *target, char *buff, size_t bufflen) static int
mnt_fs(const char *target, const char *type, char *buff, size_t bufflen)
{ {
bool bind_done = false; bool bind_done = false;
@ -128,15 +99,29 @@ static int mnt_bpffs(const char *target, char *buff, size_t bufflen)
bind_done = true; bind_done = true;
} }
if (mount("bpf", target, "bpf", 0, "mode=0700")) { if (mount(type, target, type, 0, "mode=0700")) {
snprintf(buff, bufflen, "mount -t bpf bpf %s failed: %s", snprintf(buff, bufflen, "mount -t %s %s %s failed: %s",
target, strerror(errno)); type, type, target, strerror(errno));
return -1; return -1;
} }
return 0; return 0;
} }
int mount_tracefs(const char *target)
{
char err_str[ERR_MAX_LEN];
int err;
err = mnt_fs(target, "tracefs", err_str, ERR_MAX_LEN);
if (err) {
err_str[ERR_MAX_LEN - 1] = '\0';
p_err("can't mount tracefs: %s", err_str);
}
return err;
}
int open_obj_pinned(char *path, bool quiet) int open_obj_pinned(char *path, bool quiet)
{ {
int fd; int fd;
@ -192,7 +177,13 @@ int mount_bpffs_for_pin(const char *name)
/* nothing to do if already mounted */ /* nothing to do if already mounted */
goto out_free; goto out_free;
err = mnt_bpffs(dir, err_str, ERR_MAX_LEN); if (block_mount) {
p_err("no BPF file system found, not mounting it due to --nomount option");
err = -1;
goto out_free;
}
err = mnt_fs(dir, "bpf", err_str, ERR_MAX_LEN);
if (err) { if (err) {
err_str[ERR_MAX_LEN - 1] = '\0'; err_str[ERR_MAX_LEN - 1] = '\0';
p_err("can't mount BPF file system to pin the object (%s): %s", p_err("can't mount BPF file system to pin the object (%s): %s",

Просмотреть файл

@ -1,3 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* /*
* Based on: * Based on:
* *

Просмотреть файл

@ -1,3 +1,4 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* /*
* Simple streaming JSON writer * Simple streaming JSON writer
* *
@ -19,6 +20,7 @@
#include <malloc.h> #include <malloc.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdint.h> #include <stdint.h>
#include <linux/compiler.h>
#include "json_writer.h" #include "json_writer.h"
@ -156,7 +158,8 @@ void jsonw_name(json_writer_t *self, const char *name)
putc(' ', self->out); putc(' ', self->out);
} }
void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap) void __printf(2, 0)
jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap)
{ {
jsonw_eor(self); jsonw_eor(self);
putc('"', self->out); putc('"', self->out);
@ -164,7 +167,7 @@ void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap)
putc('"', self->out); putc('"', self->out);
} }
void jsonw_printf(json_writer_t *self, const char *fmt, ...) void __printf(2, 3) jsonw_printf(json_writer_t *self, const char *fmt, ...)
{ {
va_list ap; va_list ap;

Просмотреть файл

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/* /*
* Simple streaming JSON writer * Simple streaming JSON writer
* *

Просмотреть файл

@ -1,35 +1,5 @@
/* // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
* Copyright (C) 2017-2018 Netronome Systems, Inc. /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
@ -54,6 +24,7 @@ json_writer_t *json_wtr;
bool pretty_output; bool pretty_output;
bool json_output; bool json_output;
bool show_pinned; bool show_pinned;
bool block_mount;
int bpf_flags; int bpf_flags;
struct pinned_obj_table prog_table; struct pinned_obj_table prog_table;
struct pinned_obj_table map_table; struct pinned_obj_table map_table;
@ -343,6 +314,7 @@ int main(int argc, char **argv)
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{ "bpffs", no_argument, NULL, 'f' }, { "bpffs", no_argument, NULL, 'f' },
{ "mapcompat", no_argument, NULL, 'm' }, { "mapcompat", no_argument, NULL, 'm' },
{ "nomount", no_argument, NULL, 'n' },
{ 0 } { 0 }
}; };
int opt, ret; int opt, ret;
@ -351,13 +323,14 @@ int main(int argc, char **argv)
pretty_output = false; pretty_output = false;
json_output = false; json_output = false;
show_pinned = false; show_pinned = false;
block_mount = false;
bin_name = argv[0]; bin_name = argv[0];
hash_init(prog_table.table); hash_init(prog_table.table);
hash_init(map_table.table); hash_init(map_table.table);
opterr = 0; opterr = 0;
while ((opt = getopt_long(argc, argv, "Vhpjfm", while ((opt = getopt_long(argc, argv, "Vhpjfmn",
options, NULL)) >= 0) { options, NULL)) >= 0) {
switch (opt) { switch (opt) {
case 'V': case 'V':
@ -384,6 +357,9 @@ int main(int argc, char **argv)
case 'm': case 'm':
bpf_flags = MAPS_RELAX_COMPAT; bpf_flags = MAPS_RELAX_COMPAT;
break; break;
case 'n':
block_mount = true;
break;
default: default:
p_err("unrecognized option '%s'", argv[optind - 1]); p_err("unrecognized option '%s'", argv[optind - 1]);
if (json_output) if (json_output)

Просмотреть файл

@ -1,35 +1,5 @@
/* /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
* Copyright (C) 2017-2018 Netronome Systems, Inc. /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __BPF_TOOL_H #ifndef __BPF_TOOL_H
#define __BPF_TOOL_H #define __BPF_TOOL_H
@ -74,7 +44,8 @@
#define HELP_SPEC_PROGRAM \ #define HELP_SPEC_PROGRAM \
"PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }" "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"
#define HELP_SPEC_OPTIONS \ #define HELP_SPEC_OPTIONS \
"OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} | {-m|--mapcompat}" "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} |\n" \
"\t {-m|--mapcompat} | {-n|--nomount} }"
#define HELP_SPEC_MAP \ #define HELP_SPEC_MAP \
"MAP := { id MAP_ID | pinned FILE }" "MAP := { id MAP_ID | pinned FILE }"
@ -115,6 +86,7 @@ extern const char *bin_name;
extern json_writer_t *json_wtr; extern json_writer_t *json_wtr;
extern bool json_output; extern bool json_output;
extern bool show_pinned; extern bool show_pinned;
extern bool block_mount;
extern int bpf_flags; extern int bpf_flags;
extern struct pinned_obj_table prog_table; extern struct pinned_obj_table prog_table;
extern struct pinned_obj_table map_table; extern struct pinned_obj_table map_table;
@ -128,6 +100,8 @@ void usage(void) __noreturn;
void set_max_rlimit(void); void set_max_rlimit(void);
int mount_tracefs(const char *target);
struct pinned_obj_table { struct pinned_obj_table {
DECLARE_HASHTABLE(table, 16); DECLARE_HASHTABLE(table, 16);
}; };
@ -177,8 +151,8 @@ int prog_parse_fd(int *argc, char ***argv);
int map_parse_fd(int *argc, char ***argv); int map_parse_fd(int *argc, char ***argv);
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
#ifdef HAVE_LIBBFD_SUPPORT
struct bpf_prog_linfo; struct bpf_prog_linfo;
#ifdef HAVE_LIBBFD_SUPPORT
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
const char *arch, const char *disassembler_options, const char *arch, const char *disassembler_options,
const struct btf *btf, const struct btf *btf,

Просмотреть файл

@ -1,35 +1,5 @@
/* // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
* Copyright (C) 2017-2018 Netronome Systems, Inc. /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>

Просмотреть файл

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright (C) 2018 Netronome Systems, Inc. */ /* Copyright (C) 2018 Netronome Systems, Inc. */
/* This program is free software; you can redistribute it and/or /* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public * modify it under the terms of version 2 of the GNU General Public

Просмотреть файл

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
// Copyright (C) 2018 Facebook // Copyright (C) 2018 Facebook
#define _GNU_SOURCE #define _GNU_SOURCE

Просмотреть файл

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
// Copyright (C) 2018 Facebook // Copyright (C) 2018 Facebook
#include <stdlib.h> #include <stdlib.h>

Просмотреть файл

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+ /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
// Copyright (C) 2018 Facebook // Copyright (C) 2018 Facebook
#ifndef _NETLINK_DUMPER_H_ #ifndef _NETLINK_DUMPER_H_

Просмотреть файл

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
// Copyright (C) 2018 Facebook // Copyright (C) 2018 Facebook
// Author: Yonghong Song <yhs@fb.com> // Author: Yonghong Song <yhs@fb.com>

Просмотреть файл

@ -1,35 +1,5 @@
/* // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
* Copyright (C) 2017-2018 Netronome Systems, Inc. /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#define _GNU_SOURCE #define _GNU_SOURCE
#include <errno.h> #include <errno.h>
@ -62,7 +32,7 @@ static const char * const attach_type_strings[] = {
[__MAX_BPF_ATTACH_TYPE] = NULL, [__MAX_BPF_ATTACH_TYPE] = NULL,
}; };
enum bpf_attach_type parse_attach_type(const char *str) static enum bpf_attach_type parse_attach_type(const char *str)
{ {
enum bpf_attach_type type; enum bpf_attach_type type;
@ -626,13 +596,6 @@ static int do_dump(int argc, char **argv)
goto err_free; goto err_free;
} }
if (func_info && !info.func_info) {
/* kernel.kptr_restrict is set. No func_info available. */
free(func_info);
func_info = NULL;
nr_finfo = 0;
}
if (linfo && info.nr_line_info != nr_linfo) { if (linfo && info.nr_line_info != nr_linfo) {
p_err("incorrect nr_line_info %u vs. expected %u", p_err("incorrect nr_line_info %u vs. expected %u",
info.nr_line_info, nr_linfo); info.nr_line_info, nr_linfo);
@ -835,7 +798,7 @@ struct map_replace {
char *name; char *name;
}; };
int map_replace_compar(const void *p1, const void *p2) static int map_replace_compar(const void *p1, const void *p2)
{ {
const struct map_replace *a = p1, *b = p2; const struct map_replace *a = p1, *b = p2;

Просмотреть файл

@ -54,7 +54,7 @@ find_tracefs_mnt_single(unsigned long magic, char *mnt, const char *mntpt)
return true; return true;
} }
static bool find_tracefs_pipe(char *mnt) static bool get_tracefs_pipe(char *mnt)
{ {
static const char * const known_mnts[] = { static const char * const known_mnts[] = {
"/sys/kernel/debug/tracing", "/sys/kernel/debug/tracing",
@ -88,7 +88,20 @@ static bool find_tracefs_pipe(char *mnt)
fclose(fp); fclose(fp);
/* The string from fscanf() might be truncated, check mnt is valid */ /* The string from fscanf() might be truncated, check mnt is valid */
if (!found || validate_tracefs_mnt(mnt, TRACEFS_MAGIC)) if (found && validate_tracefs_mnt(mnt, TRACEFS_MAGIC))
goto exit_found;
if (block_mount)
return false;
p_info("could not find tracefs, attempting to mount it now");
/* Most of the time, tracefs is automatically mounted by debugfs at
* /sys/kernel/debug/tracing when we try to access it. If we could not
* find it, it is likely that debugfs is not mounted. Let's give one
* attempt at mounting just tracefs at /sys/kernel/tracing.
*/
strcpy(mnt, known_mnts[1]);
if (mount_tracefs(mnt))
return false; return false;
exit_found: exit_found:
@ -115,17 +128,13 @@ int do_tracelog(int argc, char **argv)
.sa_handler = exit_tracelog .sa_handler = exit_tracelog
}; };
char trace_pipe[PATH_MAX]; char trace_pipe[PATH_MAX];
bool found_trace_pipe;
size_t buff_len = 0; size_t buff_len = 0;
if (json_output) if (json_output)
jsonw_start_array(json_wtr); jsonw_start_array(json_wtr);
found_trace_pipe = find_tracefs_pipe(trace_pipe); if (!get_tracefs_pipe(trace_pipe))
if (!found_trace_pipe) {
p_err("could not find trace pipe, tracefs not mounted?");
return -1; return -1;
}
trace_pipe_fd = fopen(trace_pipe, "r"); trace_pipe_fd = fopen(trace_pipe, "r");
if (!trace_pipe_fd) { if (!trace_pipe_fd) {

Просмотреть файл

@ -1,39 +1,5 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* /* Copyright (C) 2018 Netronome Systems, Inc. */
* Copyright (C) 2018 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#define _GNU_SOURCE #define _GNU_SOURCE
#include <stdarg.h> #include <stdarg.h>
@ -115,7 +81,7 @@ struct kernel_sym *kernel_syms_search(struct dump_data *dd,
sizeof(*dd->sym_mapping), kernel_syms_cmp) : NULL; sizeof(*dd->sym_mapping), kernel_syms_cmp) : NULL;
} }
static void print_insn(void *private_data, const char *fmt, ...) static void __printf(2, 3) print_insn(void *private_data, const char *fmt, ...)
{ {
va_list args; va_list args;
@ -124,7 +90,7 @@ static void print_insn(void *private_data, const char *fmt, ...)
va_end(args); va_end(args);
} }
static void static void __printf(2, 3)
print_insn_for_graph(void *private_data, const char *fmt, ...) print_insn_for_graph(void *private_data, const char *fmt, ...)
{ {
char buf[64], *p; char buf[64], *p;
@ -155,7 +121,8 @@ print_insn_for_graph(void *private_data, const char *fmt, ...)
printf("%s", buf); printf("%s", buf);
} }
static void print_insn_json(void *private_data, const char *fmt, ...) static void __printf(2, 3)
print_insn_json(void *private_data, const char *fmt, ...)
{ {
unsigned int l = strlen(fmt); unsigned int l = strlen(fmt);
char chomped_fmt[l]; char chomped_fmt[l];

Просмотреть файл

@ -1,39 +1,5 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/* /* Copyright (C) 2018 Netronome Systems, Inc. */
* Copyright (C) 2018 Netronome Systems, Inc.
*
* This software is dual licensed under the GNU General License Version 2,
* June 1991 as shown in the file COPYING in the top-level directory of this
* source tree or the BSD 2-Clause License provided below. You have the
* option to license this software under the complete terms of either license.
*
* The BSD 2-Clause License:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BPF_TOOL_XLATED_DUMPER_H #ifndef __BPF_TOOL_XLATED_DUMPER_H
#define __BPF_TOOL_XLATED_DUMPER_H #define __BPF_TOOL_XLATED_DUMPER_H

Просмотреть файл

@ -133,6 +133,14 @@ enum bpf_map_type {
BPF_MAP_TYPE_STACK, BPF_MAP_TYPE_STACK,
}; };
/* Note that tracing related programs such as
* BPF_PROG_TYPE_{KPROBE,TRACEPOINT,PERF_EVENT,RAW_TRACEPOINT}
* are not subject to a stable API since kernel internal data
* structures can change from release to release and may
* therefore break existing tracing BPF programs. Tracing BPF
* programs correspond to /a/ specific kernel which is to be
* analyzed, and not /a/ specific kernel /and/ all future ones.
*/
enum bpf_prog_type { enum bpf_prog_type {
BPF_PROG_TYPE_UNSPEC, BPF_PROG_TYPE_UNSPEC,
BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_SOCKET_FILTER,
@ -343,7 +351,7 @@ union bpf_attr {
__u32 log_level; /* verbosity level of verifier */ __u32 log_level; /* verbosity level of verifier */
__u32 log_size; /* size of user buffer */ __u32 log_size; /* size of user buffer */
__aligned_u64 log_buf; /* user supplied buffer */ __aligned_u64 log_buf; /* user supplied buffer */
__u32 kern_version; /* checked when prog_type=kprobe */ __u32 kern_version; /* not used */
__u32 prog_flags; __u32 prog_flags;
char prog_name[BPF_OBJ_NAME_LEN]; char prog_name[BPF_OBJ_NAME_LEN];
__u32 prog_ifindex; /* ifindex of netdev to prep for */ __u32 prog_ifindex; /* ifindex of netdev to prep for */
@ -2657,6 +2665,7 @@ struct sk_msg_md {
__u32 local_ip6[4]; /* Stored in network byte order */ __u32 local_ip6[4]; /* Stored in network byte order */
__u32 remote_port; /* Stored in network byte order */ __u32 remote_port; /* Stored in network byte order */
__u32 local_port; /* stored in host byte order */ __u32 local_port; /* stored in host byte order */
__u32 size; /* Total size of sk_msg */
}; };
struct sk_reuseport_md { struct sk_reuseport_md {
@ -2717,6 +2726,8 @@ struct bpf_prog_info {
__u32 nr_jited_line_info; __u32 nr_jited_line_info;
__u32 line_info_rec_size; __u32 line_info_rec_size;
__u32 jited_line_info_rec_size; __u32 jited_line_info_rec_size;
__u32 nr_prog_tags;
__aligned_u64 prog_tags;
} __attribute__((aligned(8))); } __attribute__((aligned(8)));
struct bpf_map_info { struct bpf_map_info {

Просмотреть файл

@ -34,7 +34,9 @@ struct btf_type {
* bits 0-15: vlen (e.g. # of struct's members) * bits 0-15: vlen (e.g. # of struct's members)
* bits 16-23: unused * bits 16-23: unused
* bits 24-27: kind (e.g. int, ptr, array...etc) * bits 24-27: kind (e.g. int, ptr, array...etc)
* bits 28-31: unused * bits 28-30: unused
* bit 31: kind_flag, currently used by
* struct, union and fwd
*/ */
__u32 info; __u32 info;
/* "size" is used by INT, ENUM, STRUCT and UNION. /* "size" is used by INT, ENUM, STRUCT and UNION.
@ -52,6 +54,7 @@ struct btf_type {
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f) #define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
#define BTF_INFO_VLEN(info) ((info) & 0xffff) #define BTF_INFO_VLEN(info) ((info) & 0xffff)
#define BTF_INFO_KFLAG(info) ((info) >> 31)
#define BTF_KIND_UNKN 0 /* Unknown */ #define BTF_KIND_UNKN 0 /* Unknown */
#define BTF_KIND_INT 1 /* Integer */ #define BTF_KIND_INT 1 /* Integer */
@ -110,9 +113,22 @@ struct btf_array {
struct btf_member { struct btf_member {
__u32 name_off; __u32 name_off;
__u32 type; __u32 type;
__u32 offset; /* offset in bits */ /* If the type info kind_flag is set, the btf_member offset
* contains both member bitfield size and bit offset. The
* bitfield size is set for bitfield members. If the type
* info kind_flag is not set, the offset contains only bit
* offset.
*/
__u32 offset;
}; };
/* If the struct/union type info kind_flag is set, the
* following two macros are used to access bitfield_size
* and bit_offset from btf_member.offset.
*/
#define BTF_MEMBER_BITFIELD_SIZE(val) ((val) >> 24)
#define BTF_MEMBER_BIT_OFFSET(val) ((val) & 0xffffff)
/* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param". /* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
* The exact number of btf_param is stored in the vlen (of the * The exact number of btf_param is stored in the vlen (of the
* info in "struct btf_type"). * info in "struct btf_type").

Просмотреть файл

@ -107,11 +107,7 @@ struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
nr_linfo = info->nr_line_info; nr_linfo = info->nr_line_info;
/* if (!nr_linfo)
* Test !info->line_info because the kernel may NULL
* the ptr if kernel.kptr_restrict is set.
*/
if (!nr_linfo || !info->line_info)
return NULL; return NULL;
/* /*

Просмотреть файл

@ -266,6 +266,7 @@ void bpf_program__unload(struct bpf_program *prog)
zclose(prog->btf_fd); zclose(prog->btf_fd);
zfree(&prog->func_info); zfree(&prog->func_info);
zfree(&prog->line_info);
} }
static void bpf_program__exit(struct bpf_program *prog) static void bpf_program__exit(struct bpf_program *prog)

1
tools/testing/selftests/bpf/.gitignore поставляемый
Просмотреть файл

@ -27,3 +27,4 @@ test_flow_dissector
flow_dissector_load flow_dissector_load
test_netcnt test_netcnt
test_section_names test_section_names
test_tcpnotify_user

Просмотреть файл

@ -35,9 +35,11 @@ int connect_v4_prog(struct bpf_sock_addr *ctx)
if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM) if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
return 0; return 0;
else if (ctx->type == SOCK_STREAM) else if (ctx->type == SOCK_STREAM)
sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv4), 0, 0); sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv4),
BPF_F_CURRENT_NETNS, 0);
else else
sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv4), 0, 0); sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv4),
BPF_F_CURRENT_NETNS, 0);
if (!sk) if (!sk)
return 0; return 0;

Просмотреть файл

@ -47,9 +47,11 @@ int connect_v6_prog(struct bpf_sock_addr *ctx)
if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM) if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
return 0; return 0;
else if (ctx->type == SOCK_STREAM) else if (ctx->type == SOCK_STREAM)
sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv6), 0, 0); sk = bpf_sk_lookup_tcp(ctx, &tuple, sizeof(tuple.ipv6),
BPF_F_CURRENT_NETNS, 0);
else else
sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv6), 0, 0); sk = bpf_sk_lookup_udp(ctx, &tuple, sizeof(tuple.ipv6),
BPF_F_CURRENT_NETNS, 0);
if (!sk) if (!sk)
return 0; return 0;

Просмотреть файл

@ -16,12 +16,18 @@ struct bpf_map_def SEC("maps") percpu_netcnt = {
.value_size = sizeof(struct percpu_net_cnt), .value_size = sizeof(struct percpu_net_cnt),
}; };
BPF_ANNOTATE_KV_PAIR(percpu_netcnt, struct bpf_cgroup_storage_key,
struct percpu_net_cnt);
struct bpf_map_def SEC("maps") netcnt = { struct bpf_map_def SEC("maps") netcnt = {
.type = BPF_MAP_TYPE_CGROUP_STORAGE, .type = BPF_MAP_TYPE_CGROUP_STORAGE,
.key_size = sizeof(struct bpf_cgroup_storage_key), .key_size = sizeof(struct bpf_cgroup_storage_key),
.value_size = sizeof(struct net_cnt), .value_size = sizeof(struct net_cnt),
}; };
BPF_ANNOTATE_KV_PAIR(netcnt, struct bpf_cgroup_storage_key,
struct net_cnt);
SEC("cgroup/skb") SEC("cgroup/skb")
int bpf_nextcnt(struct __sk_buff *skb) int bpf_nextcnt(struct __sk_buff *skb)
{ {

Просмотреть файл

@ -65,8 +65,8 @@ static int __base_pr(const char *format, ...)
return err; return err;
} }
#define BTF_INFO_ENC(kind, root, vlen) \ #define BTF_INFO_ENC(kind, kind_flag, vlen) \
((!!(root) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN)) ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
#define BTF_TYPE_ENC(name, info, size_or_type) \ #define BTF_TYPE_ENC(name, info, size_or_type) \
(name), (info), (size_or_type) (name), (info), (size_or_type)
@ -86,6 +86,8 @@ static int __base_pr(const char *format, ...)
#define BTF_MEMBER_ENC(name, type, bits_offset) \ #define BTF_MEMBER_ENC(name, type, bits_offset) \
(name), (type), (bits_offset) (name), (type), (bits_offset)
#define BTF_ENUM_ENC(name, val) (name), (val) #define BTF_ENUM_ENC(name, val) (name), (val)
#define BTF_MEMBER_OFFSET(bitfield_size, bits_offset) \
((bitfield_size) << 24 | (bits_offset))
#define BTF_TYPEDEF_ENC(name, type) \ #define BTF_TYPEDEF_ENC(name, type) \
BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0), type) BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0), type)
@ -2215,6 +2217,496 @@ static struct btf_raw_test raw_tests[] = {
.err_str = "Invalid type_id", .err_str = "Invalid type_id",
}, },
{
.descr = "invalid int kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_INT, 1, 0), 4), /* [2] */
BTF_INT_ENC(0, 0, 32),
BTF_END_RAW,
},
BTF_STR_SEC(""),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "int_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid btf_info kind_flag",
},
{
.descr = "invalid ptr kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 1, 0), 1), /* [2] */
BTF_END_RAW,
},
BTF_STR_SEC(""),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "ptr_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid btf_info kind_flag",
},
{
.descr = "invalid array kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ARRAY, 1, 0), 0), /* [2] */
BTF_ARRAY_ENC(1, 1, 1),
BTF_END_RAW,
},
BTF_STR_SEC(""),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "array_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid btf_info kind_flag",
},
{
.descr = "invalid enum kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 1, 1), 4), /* [2] */
BTF_ENUM_ENC(NAME_TBD, 0),
BTF_END_RAW,
},
BTF_STR_SEC("\0A"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "enum_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid btf_info kind_flag",
},
{
.descr = "valid fwd kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(NAME_TBD,
BTF_INFO_ENC(BTF_KIND_FWD, 1, 0), 0), /* [2] */
BTF_END_RAW,
},
BTF_STR_SEC("\0A"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "fwd_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
},
{
.descr = "invalid typedef kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(NAME_TBD,
BTF_INFO_ENC(BTF_KIND_TYPEDEF, 1, 0), 1), /* [2] */
BTF_END_RAW,
},
BTF_STR_SEC("\0A"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "typedef_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid btf_info kind_flag",
},
{
.descr = "invalid volatile kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_VOLATILE, 1, 0), 1), /* [2] */
BTF_END_RAW,
},
BTF_STR_SEC(""),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "volatile_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid btf_info kind_flag",
},
{
.descr = "invalid const kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 1, 0), 1), /* [2] */
BTF_END_RAW,
},
BTF_STR_SEC(""),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "const_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid btf_info kind_flag",
},
{
.descr = "invalid restrict kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_RESTRICT, 1, 0), 1), /* [2] */
BTF_END_RAW,
},
BTF_STR_SEC(""),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "restrict_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid btf_info kind_flag",
},
{
.descr = "invalid func kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 0), 0), /* [2] */
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 1, 0), 2), /* [3] */
BTF_END_RAW,
},
BTF_STR_SEC("\0A"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "func_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid btf_info kind_flag",
},
{
.descr = "invalid func_proto kind_flag",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 1, 0), 0), /* [2] */
BTF_END_RAW,
},
BTF_STR_SEC(""),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "func_proto_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid btf_info kind_flag",
},
{
.descr = "valid struct, kind_flag, bitfield_size = 0",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 8), /* [2] */
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(0, 0)),
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(0, 32)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
},
{
.descr = "valid struct, kind_flag, int member, bitfield_size != 0",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4), /* [2] */
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(4, 0)),
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(4, 4)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
},
{
.descr = "valid union, kind_flag, int member, bitfield_size != 0",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 1, 2), 4), /* [2] */
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(4, 0)),
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(4, 0)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "union_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
},
{
.descr = "valid struct, kind_flag, enum member, bitfield_size != 0",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [2] */
BTF_ENUM_ENC(NAME_TBD, 0),
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4),/* [3] */
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(4, 0)),
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(4, 4)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B\0C"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
},
{
.descr = "valid union, kind_flag, enum member, bitfield_size != 0",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [2] */
BTF_ENUM_ENC(NAME_TBD, 0),
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 1, 2), 4), /* [3] */
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(4, 0)),
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(4, 0)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B\0C"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "union_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
},
{
.descr = "valid struct, kind_flag, typedef member, bitfield_size != 0",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [2] */
BTF_ENUM_ENC(NAME_TBD, 0),
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4),/* [3] */
BTF_MEMBER_ENC(NAME_TBD, 4, BTF_MEMBER_OFFSET(4, 0)),
BTF_MEMBER_ENC(NAME_TBD, 5, BTF_MEMBER_OFFSET(4, 4)),
BTF_TYPEDEF_ENC(NAME_TBD, 1), /* [4] */
BTF_TYPEDEF_ENC(NAME_TBD, 2), /* [5] */
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B\0C\0D\0E"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
},
{
.descr = "valid union, kind_flag, typedef member, bitfield_size != 0",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [2] */
BTF_ENUM_ENC(NAME_TBD, 0),
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 1, 2), 4), /* [3] */
BTF_MEMBER_ENC(NAME_TBD, 4, BTF_MEMBER_OFFSET(4, 0)),
BTF_MEMBER_ENC(NAME_TBD, 5, BTF_MEMBER_OFFSET(4, 0)),
BTF_TYPEDEF_ENC(NAME_TBD, 1), /* [4] */
BTF_TYPEDEF_ENC(NAME_TBD, 2), /* [5] */
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B\0C\0D\0E"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "union_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
},
{
.descr = "invalid struct, kind_flag, bitfield_size greater than struct size",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4), /* [2] */
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(20, 0)),
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(20, 20)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Member exceeds struct_size",
},
{
.descr = "invalid struct, kind_flag, bitfield base_type int not regular",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 20, 4), /* [2] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4), /* [3] */
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(20, 0)),
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(20, 20)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid member base type",
},
{
.descr = "invalid struct, kind_flag, base_type int not regular",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 12, 4), /* [2] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 4), /* [3] */
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(8, 0)),
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(8, 8)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid member base type",
},
{
.descr = "invalid union, kind_flag, bitfield_size greater than struct size",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 1, 2), 2), /* [2] */
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(8, 0)),
BTF_MEMBER_ENC(NAME_TBD, 1, BTF_MEMBER_OFFSET(20, 0)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "union_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Member exceeds struct_size",
},
{
.descr = "invalid struct, kind_flag, int member, bitfield_size = 0, wrong byte alignment",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [2] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 12), /* [3] */
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 0)),
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 36)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid member offset",
},
{
.descr = "invalid struct, kind_flag, enum member, bitfield_size = 0, wrong byte alignment",
.raw_types = {
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [2] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4), /* [2] */
BTF_ENUM_ENC(NAME_TBD, 0),
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 2), 12), /* [3] */
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 0)),
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 36)),
BTF_END_RAW,
},
BTF_STR_SEC("\0A\0B\0C"),
.map_type = BPF_MAP_TYPE_ARRAY,
.map_name = "struct_type_check_btf",
.key_size = sizeof(int),
.value_size = sizeof(int),
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 4,
.btf_load_err = true,
.err_str = "Invalid member offset",
},
}; /* struct btf_raw_test raw_tests[] */ }; /* struct btf_raw_test raw_tests[] */
static const char *get_next_str(const char *start, const char *end) static const char *get_next_str(const char *start, const char *end)
@ -2916,7 +3408,7 @@ static int do_test_file(unsigned int test_num)
goto done; goto done;
} }
rec_size = info.func_info_rec_size; rec_size = info.func_info_rec_size;
if (CHECK(rec_size < 4, if (CHECK(rec_size != sizeof(struct bpf_func_info),
"incorrect info.func_info_rec_size (1st) %d\n", rec_size)) { "incorrect info.func_info_rec_size (1st) %d\n", rec_size)) {
err = -1; err = -1;
goto done; goto done;
@ -3036,7 +3528,8 @@ struct pprint_mapv {
} aenum; } aenum;
}; };
static struct btf_raw_test pprint_test_template = { static struct btf_raw_test pprint_test_template[] = {
{
.raw_types = { .raw_types = {
/* unsighed char */ /* [1] */ /* unsighed char */ /* [1] */
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1), BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
@ -3086,13 +3579,140 @@ static struct btf_raw_test pprint_test_template = {
BTF_MEMBER_ENC(NAME_TBD, 15, 192), /* aenum */ BTF_MEMBER_ENC(NAME_TBD, 15, 192), /* aenum */
BTF_END_RAW, BTF_END_RAW,
}, },
.str_sec = "\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum", BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"),
.str_sec_size = sizeof("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"),
.key_size = sizeof(unsigned int), .key_size = sizeof(unsigned int),
.value_size = sizeof(struct pprint_mapv), .value_size = sizeof(struct pprint_mapv),
.key_type_id = 3, /* unsigned int */ .key_type_id = 3, /* unsigned int */
.value_type_id = 16, /* struct pprint_mapv */ .value_type_id = 16, /* struct pprint_mapv */
.max_entries = 128 * 1024, .max_entries = 128 * 1024,
},
{
/* this type will have the same type as the
* first .raw_types definition, but struct type will
* be encoded with kind_flag set.
*/
.raw_types = {
/* unsighed char */ /* [1] */
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
/* unsigned short */ /* [2] */
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
/* unsigned int */ /* [3] */
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
/* int */ /* [4] */
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
/* unsigned long long */ /* [5] */
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [6] */
BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [7] */
/* uint8_t[8] */ /* [8] */
BTF_TYPE_ARRAY_ENC(9, 1, 8),
/* typedef unsigned char uint8_t */ /* [9] */
BTF_TYPEDEF_ENC(NAME_TBD, 1),
/* typedef unsigned short uint16_t */ /* [10] */
BTF_TYPEDEF_ENC(NAME_TBD, 2),
/* typedef unsigned int uint32_t */ /* [11] */
BTF_TYPEDEF_ENC(NAME_TBD, 3),
/* typedef int int32_t */ /* [12] */
BTF_TYPEDEF_ENC(NAME_TBD, 4),
/* typedef unsigned long long uint64_t *//* [13] */
BTF_TYPEDEF_ENC(NAME_TBD, 5),
/* union (anon) */ /* [14] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
/* enum (anon) */ /* [15] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
BTF_ENUM_ENC(NAME_TBD, 0),
BTF_ENUM_ENC(NAME_TBD, 1),
BTF_ENUM_ENC(NAME_TBD, 2),
BTF_ENUM_ENC(NAME_TBD, 3),
/* struct pprint_mapv */ /* [16] */
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 8), 32),
BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)), /* uint32_t ui32 */
BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* uint16_t ui16 */
BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* int32_t si32 */
BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 96)), /* unused_bits2a */
BTF_MEMBER_ENC(NAME_TBD, 7, BTF_MEMBER_OFFSET(28, 98)), /* bits28 */
BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 126)), /* unused_bits2b */
BTF_MEMBER_ENC(0, 14, BTF_MEMBER_OFFSET(0, 128)), /* union (anon) */
BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)), /* aenum */
BTF_END_RAW,
},
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"),
.key_size = sizeof(unsigned int),
.value_size = sizeof(struct pprint_mapv),
.key_type_id = 3, /* unsigned int */
.value_type_id = 16, /* struct pprint_mapv */
.max_entries = 128 * 1024,
},
{
/* this type will have the same layout as the
* first .raw_types definition. The struct type will
* be encoded with kind_flag set, bitfield members
* are added typedef/const/volatile, and bitfield members
* will have both int and enum types.
*/
.raw_types = {
/* unsighed char */ /* [1] */
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
/* unsigned short */ /* [2] */
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
/* unsigned int */ /* [3] */
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
/* int */ /* [4] */
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
/* unsigned long long */ /* [5] */
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [6] */
BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [7] */
/* uint8_t[8] */ /* [8] */
BTF_TYPE_ARRAY_ENC(9, 1, 8),
/* typedef unsigned char uint8_t */ /* [9] */
BTF_TYPEDEF_ENC(NAME_TBD, 1),
/* typedef unsigned short uint16_t */ /* [10] */
BTF_TYPEDEF_ENC(NAME_TBD, 2),
/* typedef unsigned int uint32_t */ /* [11] */
BTF_TYPEDEF_ENC(NAME_TBD, 3),
/* typedef int int32_t */ /* [12] */
BTF_TYPEDEF_ENC(NAME_TBD, 4),
/* typedef unsigned long long uint64_t *//* [13] */
BTF_TYPEDEF_ENC(NAME_TBD, 5),
/* union (anon) */ /* [14] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
/* enum (anon) */ /* [15] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
BTF_ENUM_ENC(NAME_TBD, 0),
BTF_ENUM_ENC(NAME_TBD, 1),
BTF_ENUM_ENC(NAME_TBD, 2),
BTF_ENUM_ENC(NAME_TBD, 3),
/* struct pprint_mapv */ /* [16] */
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 8), 32),
BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)), /* uint32_t ui32 */
BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* uint16_t ui16 */
BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* int32_t si32 */
BTF_MEMBER_ENC(NAME_TBD, 17, BTF_MEMBER_OFFSET(2, 96)), /* unused_bits2a */
BTF_MEMBER_ENC(NAME_TBD, 7, BTF_MEMBER_OFFSET(28, 98)), /* bits28 */
BTF_MEMBER_ENC(NAME_TBD, 19, BTF_MEMBER_OFFSET(2, 126)),/* unused_bits2b */
BTF_MEMBER_ENC(0, 14, BTF_MEMBER_OFFSET(0, 128)), /* union (anon) */
BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)), /* aenum */
/* typedef unsigned int ___int */ /* [17] */
BTF_TYPEDEF_ENC(NAME_TBD, 18),
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_VOLATILE, 0, 0), 6), /* [18] */
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 15), /* [19] */
BTF_END_RAW,
},
BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0___int"),
.key_size = sizeof(unsigned int),
.value_size = sizeof(struct pprint_mapv),
.key_type_id = 3, /* unsigned int */
.value_type_id = 16, /* struct pprint_mapv */
.max_entries = 128 * 1024,
},
}; };
static struct btf_pprint_test_meta { static struct btf_pprint_test_meta {
@ -3195,9 +3815,9 @@ static int check_line(const char *expected_line, int nexpected_line,
} }
static int do_test_pprint(void) static int do_test_pprint(int test_num)
{ {
const struct btf_raw_test *test = &pprint_test_template; const struct btf_raw_test *test = &pprint_test_template[test_num];
struct bpf_create_map_attr create_attr = {}; struct bpf_create_map_attr create_attr = {};
bool ordered_map, lossless_map, percpu_map; bool ordered_map, lossless_map, percpu_map;
int err, ret, num_cpus, rounded_value_size; int err, ret, num_cpus, rounded_value_size;
@ -3213,7 +3833,7 @@ static int do_test_pprint(void)
uint8_t *raw_btf; uint8_t *raw_btf;
ssize_t nread; ssize_t nread;
fprintf(stderr, "%s......", test->descr); fprintf(stderr, "%s(#%d)......", test->descr, test_num);
raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
test->str_sec, test->str_sec_size, test->str_sec, test->str_sec_size,
&raw_btf_size, NULL); &raw_btf_size, NULL);
@ -3406,15 +4026,27 @@ static int test_pprint(void)
unsigned int i; unsigned int i;
int err = 0; int err = 0;
/* test various maps with the first test template */
for (i = 0; i < ARRAY_SIZE(pprint_tests_meta); i++) { for (i = 0; i < ARRAY_SIZE(pprint_tests_meta); i++) {
pprint_test_template.descr = pprint_tests_meta[i].descr; pprint_test_template[0].descr = pprint_tests_meta[i].descr;
pprint_test_template.map_type = pprint_tests_meta[i].map_type; pprint_test_template[0].map_type = pprint_tests_meta[i].map_type;
pprint_test_template.map_name = pprint_tests_meta[i].map_name; pprint_test_template[0].map_name = pprint_tests_meta[i].map_name;
pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map; pprint_test_template[0].ordered_map = pprint_tests_meta[i].ordered_map;
pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map; pprint_test_template[0].lossless_map = pprint_tests_meta[i].lossless_map;
pprint_test_template.percpu_map = pprint_tests_meta[i].percpu_map; pprint_test_template[0].percpu_map = pprint_tests_meta[i].percpu_map;
err |= count_result(do_test_pprint()); err |= count_result(do_test_pprint(0));
}
/* test rest test templates with the first map */
for (i = 1; i < ARRAY_SIZE(pprint_test_template); i++) {
pprint_test_template[i].descr = pprint_tests_meta[0].descr;
pprint_test_template[i].map_type = pprint_tests_meta[0].map_type;
pprint_test_template[i].map_name = pprint_tests_meta[0].map_name;
pprint_test_template[i].ordered_map = pprint_tests_meta[0].ordered_map;
pprint_test_template[i].lossless_map = pprint_tests_meta[0].lossless_map;
pprint_test_template[i].percpu_map = pprint_tests_meta[0].percpu_map;
err |= count_result(do_test_pprint(i));
} }
return err; return err;
@ -3621,6 +4253,33 @@ static struct prog_info_raw_test {
.expected_prog_load_failure = true, .expected_prog_load_failure = true,
}, },
{
.descr = "line_info (Zero bpf insn code)",
.raw_types = {
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8), /* [2] */
BTF_TYPEDEF_ENC(NAME_TBD, 2), /* [3] */
BTF_END_RAW,
},
BTF_STR_SEC("\0int\0unsigned long\0u64\0u64 a=1;\0return a;"),
.insns = {
BPF_LD_IMM64(BPF_REG_0, 1),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
.func_info_cnt = 0,
.line_info = {
BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10),
BPF_LINE_INFO_ENC(1, 0, 0, 2, 9),
BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 3, 8),
BTF_END_RAW,
},
.line_info_rec_size = sizeof(struct bpf_line_info),
.nr_jited_ksyms = 1,
.err_str = "Invalid insn code at line_info[1]",
.expected_prog_load_failure = true,
},
{ {
.descr = "line_info (No subprog. zero tailing line_info", .descr = "line_info (No subprog. zero tailing line_info",
.raw_types = { .raw_types = {
@ -3912,7 +4571,7 @@ static int test_get_finfo(const struct prog_info_raw_test *test,
} }
rec_size = info.func_info_rec_size; rec_size = info.func_info_rec_size;
if (CHECK(rec_size < 8, if (CHECK(rec_size != sizeof(struct bpf_func_info),
"incorrect info.func_info_rec_size (1st) %d", rec_size)) { "incorrect info.func_info_rec_size (1st) %d", rec_size)) {
return -1; return -1;
} }
@ -3941,19 +4600,13 @@ static int test_get_finfo(const struct prog_info_raw_test *test,
err = -1; err = -1;
goto done; goto done;
} }
if (CHECK(info.func_info_rec_size < 8, if (CHECK(info.func_info_rec_size != rec_size,
"incorrect info.func_info_rec_size (2nd) %d", "incorrect info.func_info_rec_size (2nd) %d",
info.func_info_rec_size)) { info.func_info_rec_size)) {
err = -1; err = -1;
goto done; goto done;
} }
if (CHECK(!info.func_info,
"info.func_info == 0. kernel.kptr_restrict is set?")) {
err = -1;
goto done;
}
finfo = func_info; finfo = func_info;
for (i = 0; i < test->func_info_cnt; i++) { for (i = 0; i < test->func_info_cnt; i++) {
if (CHECK(finfo->type_id != test->func_info[i][1], if (CHECK(finfo->type_id != test->func_info[i][1],
@ -4023,8 +4676,8 @@ static int test_get_linfo(const struct prog_info_raw_test *test,
goto done; goto done;
} }
if (CHECK(info.line_info_rec_size < 16 || if (CHECK(info.line_info_rec_size != sizeof(struct bpf_line_info) ||
info.jited_line_info_rec_size < 8, info.jited_line_info_rec_size != sizeof(__u64),
"info: line_info_rec_size:%u(userspace expected:%u) jited_line_info_rec_size:%u(userspace expected:%u)", "info: line_info_rec_size:%u(userspace expected:%u) jited_line_info_rec_size:%u(userspace expected:%u)",
info.line_info_rec_size, rec_size, info.line_info_rec_size, rec_size,
info.jited_line_info_rec_size, jited_rec_size)) { info.jited_line_info_rec_size, jited_rec_size)) {
@ -4077,7 +4730,6 @@ static int test_get_linfo(const struct prog_info_raw_test *test,
* Other fields are not the concern of this test. * Other fields are not the concern of this test.
*/ */
if (CHECK(err == -1 || if (CHECK(err == -1 ||
!info.line_info ||
info.nr_line_info != cnt || info.nr_line_info != cnt ||
(jited_cnt && !info.jited_line_info) || (jited_cnt && !info.jited_line_info) ||
info.nr_jited_line_info != jited_cnt || info.nr_jited_line_info != jited_cnt ||

Просмотреть файл

@ -51,10 +51,10 @@ static struct {
struct iphdr iph; struct iphdr iph;
struct tcphdr tcp; struct tcphdr tcp;
} __packed pkt_v4 = { } __packed pkt_v4 = {
.eth.h_proto = bpf_htons(ETH_P_IP), .eth.h_proto = __bpf_constant_htons(ETH_P_IP),
.iph.ihl = 5, .iph.ihl = 5,
.iph.protocol = 6, .iph.protocol = 6,
.iph.tot_len = bpf_htons(MAGIC_BYTES), .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
.tcp.urg_ptr = 123, .tcp.urg_ptr = 123,
}; };
@ -64,9 +64,9 @@ static struct {
struct ipv6hdr iph; struct ipv6hdr iph;
struct tcphdr tcp; struct tcphdr tcp;
} __packed pkt_v6 = { } __packed pkt_v6 = {
.eth.h_proto = bpf_htons(ETH_P_IPV6), .eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
.iph.nexthdr = 6, .iph.nexthdr = 6,
.iph.payload_len = bpf_htons(MAGIC_BYTES), .iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
.tcp.urg_ptr = 123, .tcp.urg_ptr = 123,
}; };

Просмотреть файл

@ -49,6 +49,7 @@
#define MAX_INSNS BPF_MAXINSNS #define MAX_INSNS BPF_MAXINSNS
#define MAX_FIXUPS 8 #define MAX_FIXUPS 8
#define MAX_NR_MAPS 13 #define MAX_NR_MAPS 13
#define MAX_TEST_RUNS 8
#define POINTER_VALUE 0xcafe4all #define POINTER_VALUE 0xcafe4all
#define TEST_DATA_LEN 64 #define TEST_DATA_LEN 64
@ -76,7 +77,7 @@ struct bpf_test {
int fixup_percpu_cgroup_storage[MAX_FIXUPS]; int fixup_percpu_cgroup_storage[MAX_FIXUPS];
const char *errstr; const char *errstr;
const char *errstr_unpriv; const char *errstr_unpriv;
uint32_t retval, retval_unpriv; uint32_t retval, retval_unpriv, insn_processed;
enum { enum {
UNDEF, UNDEF,
ACCEPT, ACCEPT,
@ -86,6 +87,14 @@ struct bpf_test {
uint8_t flags; uint8_t flags;
__u8 data[TEST_DATA_LEN]; __u8 data[TEST_DATA_LEN];
void (*fill_helper)(struct bpf_test *self); void (*fill_helper)(struct bpf_test *self);
uint8_t runs;
struct {
uint32_t retval, retval_unpriv;
union {
__u8 data[TEST_DATA_LEN];
__u64 data64[TEST_DATA_LEN / 8];
};
} retvals[MAX_TEST_RUNS];
}; };
/* Note we want this to be 64 bit aligned so that the end of our array is /* Note we want this to be 64 bit aligned so that the end of our array is
@ -1001,13 +1010,43 @@ static struct bpf_test tests[] = {
BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8),
/* mess up with R1 pointer on stack */ /* mess up with R1 pointer on stack */
BPF_ST_MEM(BPF_B, BPF_REG_10, -7, 0x23), BPF_ST_MEM(BPF_B, BPF_REG_10, -7, 0x23),
/* fill back into R0 should fail */ /* fill back into R0 is fine for priv.
* R0 now becomes SCALAR_VALUE.
*/
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8),
/* Load from R0 should fail. */
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 8),
BPF_EXIT_INSN(),
},
.errstr_unpriv = "attempt to corrupt spilled",
.errstr = "R0 invalid mem access 'inv",
.result = REJECT,
},
{
"check corrupted spill/fill, LSB",
.insns = {
BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8),
BPF_ST_MEM(BPF_H, BPF_REG_10, -8, 0xcafe),
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8),
BPF_EXIT_INSN(), BPF_EXIT_INSN(),
}, },
.errstr_unpriv = "attempt to corrupt spilled", .errstr_unpriv = "attempt to corrupt spilled",
.errstr = "corrupted spill", .result_unpriv = REJECT,
.result = REJECT, .result = ACCEPT,
.retval = POINTER_VALUE,
},
{
"check corrupted spill/fill, MSB",
.insns = {
BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8),
BPF_ST_MEM(BPF_W, BPF_REG_10, -4, 0x12345678),
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8),
BPF_EXIT_INSN(),
},
.errstr_unpriv = "attempt to corrupt spilled",
.result_unpriv = REJECT,
.result = ACCEPT,
.retval = POINTER_VALUE,
}, },
{ {
"invalid src register in STX", "invalid src register in STX",
@ -1813,10 +1852,20 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SK_SKB, .prog_type = BPF_PROG_TYPE_SK_SKB,
}, },
{ {
"invalid 64B read of family in SK_MSG", "valid access size in SK_MSG",
.insns = {
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
offsetof(struct sk_msg_md, size)),
BPF_EXIT_INSN(),
},
.result = ACCEPT,
.prog_type = BPF_PROG_TYPE_SK_MSG,
},
{
"invalid 64B read of size in SK_MSG",
.insns = { .insns = {
BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1,
offsetof(struct sk_msg_md, family)), offsetof(struct sk_msg_md, size)),
BPF_EXIT_INSN(), BPF_EXIT_INSN(),
}, },
.errstr = "invalid bpf_context access", .errstr = "invalid bpf_context access",
@ -1827,10 +1876,10 @@ static struct bpf_test tests[] = {
"invalid read past end of SK_MSG", "invalid read past end of SK_MSG",
.insns = { .insns = {
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
offsetof(struct sk_msg_md, local_port) + 4), offsetof(struct sk_msg_md, size) + 4),
BPF_EXIT_INSN(), BPF_EXIT_INSN(),
}, },
.errstr = "R0 !read_ok", .errstr = "invalid bpf_context access",
.result = REJECT, .result = REJECT,
.prog_type = BPF_PROG_TYPE_SK_MSG, .prog_type = BPF_PROG_TYPE_SK_MSG,
}, },
@ -13647,6 +13696,28 @@ static struct bpf_test tests[] = {
.prog_type = BPF_PROG_TYPE_SCHED_CLS, .prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT, .result = ACCEPT,
}, },
{
"allocated_stack",
.insns = {
BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_1),
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_prandom_u32),
BPF_ALU64_REG(BPF_MOV, BPF_REG_7, BPF_REG_0),
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_6, -8),
BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, -8),
BPF_STX_MEM(BPF_B, BPF_REG_10, BPF_REG_7, -9),
BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_10, -9),
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0),
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0),
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0),
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0),
BPF_EXIT_INSN(),
},
.result = ACCEPT,
.result_unpriv = ACCEPT,
.insn_processed = 15,
},
{ {
"reference tracking in call: free reference in subprog and outside", "reference tracking in call: free reference in subprog and outside",
.insns = { .insns = {
@ -14099,6 +14170,7 @@ static struct bpf_test tests[] = {
.errstr_unpriv = "R1 leaks addr", .errstr_unpriv = "R1 leaks addr",
.result = REJECT, .result = REJECT,
}, },
{
"calls: cross frame pruning", "calls: cross frame pruning",
.insns = { .insns = {
/* r8 = !!random(); /* r8 = !!random();
@ -14122,10 +14194,199 @@ static struct bpf_test tests[] = {
}, },
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER, .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
.errstr_unpriv = "function calls to other bpf functions are allowed for root only", .errstr_unpriv = "function calls to other bpf functions are allowed for root only",
.result = REJECT,
},
{
"jset: functional",
.insns = {
/* r0 = 0 */
BPF_MOV64_IMM(BPF_REG_0, 0),
/* prep for direct packet access via r2 */
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
offsetof(struct __sk_buff, data)),
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
offsetof(struct __sk_buff, data_end)),
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8),
BPF_JMP_REG(BPF_JLE, BPF_REG_4, BPF_REG_3, 1),
BPF_EXIT_INSN(),
BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0),
/* reg, bit 63 or bit 0 set, taken */
BPF_LD_IMM64(BPF_REG_8, 0x8000000000000001),
BPF_JMP_REG(BPF_JSET, BPF_REG_7, BPF_REG_8, 1),
BPF_EXIT_INSN(),
/* reg, bit 62, not taken */
BPF_LD_IMM64(BPF_REG_8, 0x4000000000000000),
BPF_JMP_REG(BPF_JSET, BPF_REG_7, BPF_REG_8, 1),
BPF_JMP_IMM(BPF_JA, 0, 0, 1),
BPF_EXIT_INSN(),
/* imm, any bit set, taken */
BPF_JMP_IMM(BPF_JSET, BPF_REG_7, -1, 1),
BPF_EXIT_INSN(),
/* imm, bit 31 set, taken */
BPF_JMP_IMM(BPF_JSET, BPF_REG_7, 0x80000000, 1),
BPF_EXIT_INSN(),
/* all good - return r0 == 2 */
BPF_MOV64_IMM(BPF_REG_0, 2),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT,
.runs = 7,
.retvals = {
{ .retval = 2,
.data64 = { (1ULL << 63) | (1U << 31) | (1U << 0), }
},
{ .retval = 2,
.data64 = { (1ULL << 63) | (1U << 31), }
},
{ .retval = 2,
.data64 = { (1ULL << 31) | (1U << 0), }
},
{ .retval = 2,
.data64 = { (__u32)-1, }
},
{ .retval = 2,
.data64 = { ~0x4000000000000000ULL, }
},
{ .retval = 0,
.data64 = { 0, }
},
{ .retval = 0,
.data64 = { ~0ULL, }
},
},
},
{
"jset: sign-extend",
.insns = {
/* r0 = 0 */
BPF_MOV64_IMM(BPF_REG_0, 0),
/* prep for direct packet access via r2 */
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
offsetof(struct __sk_buff, data)),
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
offsetof(struct __sk_buff, data_end)),
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8),
BPF_JMP_REG(BPF_JLE, BPF_REG_4, BPF_REG_3, 1),
BPF_EXIT_INSN(),
BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0),
BPF_JMP_IMM(BPF_JSET, BPF_REG_7, 0x80000000, 1),
BPF_EXIT_INSN(),
BPF_MOV64_IMM(BPF_REG_0, 2),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = ACCEPT,
.retval = 2,
.data = { 1, 0, 0, 0, 0, 0, 0, 1, },
},
{
"jset: known const compare",
.insns = {
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 1),
BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
.retval_unpriv = 1,
.result_unpriv = ACCEPT,
.retval = 1,
.result = ACCEPT,
},
{
"jset: known const compare bad",
.insns = {
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 1),
BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
.errstr_unpriv = "!read_ok",
.result_unpriv = REJECT, .result_unpriv = REJECT,
.errstr = "!read_ok", .errstr = "!read_ok",
.result = REJECT, .result = REJECT,
}, },
{
"jset: unknown const compare taken",
.insns = {
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_get_prandom_u32),
BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 1),
BPF_JMP_IMM(BPF_JA, 0, 0, 1),
BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
.errstr_unpriv = "!read_ok",
.result_unpriv = REJECT,
.errstr = "!read_ok",
.result = REJECT,
},
{
"jset: unknown const compare not taken",
.insns = {
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_get_prandom_u32),
BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 1, 1),
BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
.errstr_unpriv = "!read_ok",
.result_unpriv = REJECT,
.errstr = "!read_ok",
.result = REJECT,
},
{
"jset: half-known const compare",
.insns = {
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_get_prandom_u32),
BPF_ALU64_IMM(BPF_OR, BPF_REG_0, 2),
BPF_JMP_IMM(BPF_JSET, BPF_REG_0, 3, 1),
BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
.result_unpriv = ACCEPT,
.result = ACCEPT,
},
{
"jset: range",
.insns = {
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
BPF_FUNC_get_prandom_u32),
BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xff),
BPF_JMP_IMM(BPF_JSET, BPF_REG_1, 0xf0, 3),
BPF_JMP_IMM(BPF_JLT, BPF_REG_1, 0x10, 1),
BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
BPF_EXIT_INSN(),
BPF_JMP_IMM(BPF_JSET, BPF_REG_1, 0x10, 1),
BPF_EXIT_INSN(),
BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0x10, 1),
BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0),
BPF_EXIT_INSN(),
},
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
.result_unpriv = ACCEPT,
.result = ACCEPT,
},
}; };
static int probe_filter_length(const struct bpf_insn *fp) static int probe_filter_length(const struct bpf_insn *fp)
@ -14408,16 +14669,42 @@ out:
return ret; return ret;
} }
static int do_prog_test_run(int fd_prog, bool unpriv, uint32_t expected_val,
void *data, size_t size_data)
{
__u8 tmp[TEST_DATA_LEN << 2];
__u32 size_tmp = sizeof(tmp);
uint32_t retval;
int err;
if (unpriv)
set_admin(true);
err = bpf_prog_test_run(fd_prog, 1, data, size_data,
tmp, &size_tmp, &retval, NULL);
if (unpriv)
set_admin(false);
if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) {
printf("Unexpected bpf_prog_test_run error ");
return err;
}
if (!err && retval != expected_val &&
expected_val != POINTER_VALUE) {
printf("FAIL retval %d != %d ", retval, expected_val);
return 1;
}
return 0;
}
static void do_test_single(struct bpf_test *test, bool unpriv, static void do_test_single(struct bpf_test *test, bool unpriv,
int *passes, int *errors) int *passes, int *errors)
{ {
int fd_prog, expected_ret, alignment_prevented_execution; int fd_prog, expected_ret, alignment_prevented_execution;
int prog_len, prog_type = test->prog_type; int prog_len, prog_type = test->prog_type;
struct bpf_insn *prog = test->insns; struct bpf_insn *prog = test->insns;
int run_errs, run_successes;
int map_fds[MAX_NR_MAPS]; int map_fds[MAX_NR_MAPS];
const char *expected_err; const char *expected_err;
uint32_t expected_val;
uint32_t retval;
__u32 pflags; __u32 pflags;
int i, err; int i, err;
@ -14441,8 +14728,6 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
test->result_unpriv : test->result; test->result_unpriv : test->result;
expected_err = unpriv && test->errstr_unpriv ? expected_err = unpriv && test->errstr_unpriv ?
test->errstr_unpriv : test->errstr; test->errstr_unpriv : test->errstr;
expected_val = unpriv && test->retval_unpriv ?
test->retval_unpriv : test->retval;
alignment_prevented_execution = 0; alignment_prevented_execution = 0;
@ -14454,10 +14739,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
} }
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
if (fd_prog >= 0 && if (fd_prog >= 0 &&
(test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS)) { (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS))
alignment_prevented_execution = 1; alignment_prevented_execution = 1;
goto test_ok;
}
#endif #endif
} else { } else {
if (fd_prog >= 0) { if (fd_prog >= 0) {
@ -14471,33 +14754,67 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
} }
} }
if (fd_prog >= 0) { if (test->insn_processed) {
__u8 tmp[TEST_DATA_LEN << 2]; uint32_t insn_processed;
__u32 size_tmp = sizeof(tmp); char *proc;
if (unpriv) proc = strstr(bpf_vlog, "processed ");
set_admin(true); insn_processed = atoi(proc + 10);
err = bpf_prog_test_run(fd_prog, 1, test->data, if (test->insn_processed != insn_processed) {
sizeof(test->data), tmp, &size_tmp, printf("FAIL\nUnexpected insn_processed %u vs %u\n",
&retval, NULL); insn_processed, test->insn_processed);
if (unpriv)
set_admin(false);
if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) {
printf("Unexpected bpf_prog_test_run error\n");
goto fail_log;
}
if (!err && retval != expected_val &&
expected_val != POINTER_VALUE) {
printf("FAIL retval %d != %d\n", retval, expected_val);
goto fail_log; goto fail_log;
} }
} }
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
test_ok: run_errs = 0;
#endif run_successes = 0;
(*passes)++; if (!alignment_prevented_execution && fd_prog >= 0) {
printf("OK%s\n", alignment_prevented_execution ? uint32_t expected_val;
" (NOTE: not executed due to unknown alignment)" : ""); int i;
if (!test->runs) {
expected_val = unpriv && test->retval_unpriv ?
test->retval_unpriv : test->retval;
err = do_prog_test_run(fd_prog, unpriv, expected_val,
test->data, sizeof(test->data));
if (err)
run_errs++;
else
run_successes++;
}
for (i = 0; i < test->runs; i++) {
if (unpriv && test->retvals[i].retval_unpriv)
expected_val = test->retvals[i].retval_unpriv;
else
expected_val = test->retvals[i].retval;
err = do_prog_test_run(fd_prog, unpriv, expected_val,
test->retvals[i].data,
sizeof(test->retvals[i].data));
if (err) {
printf("(run %d/%d) ", i + 1, test->runs);
run_errs++;
} else {
run_successes++;
}
}
}
if (!run_errs) {
(*passes)++;
if (run_successes > 1)
printf("%d cases ", run_successes);
printf("OK");
if (alignment_prevented_execution)
printf(" (NOTE: not executed due to unknown alignment)");
printf("\n");
} else {
printf("\n");
goto fail_log;
}
close_fds: close_fds:
close(fd_prog); close(fd_prog);
for (i = 0; i < MAX_NR_MAPS; i++) for (i = 0; i < MAX_NR_MAPS; i++)