bpf: decode BPF_PROG_QUERY command

BPF_PROG_QUERY was introduced in Linux commit v4.15-rc1~84^2~558^2~6.

* xlat/bpf_commands.in (BPF_PROG_QUERY): New constant.
* xlat/bpf_query_flags.in: New file.
* bpf.c: Include it.
(DECL_BPF_CMD_DECODER): Add priv argument for passing tcb private data.
(BEGIN_BPF_CMD_DECODER(BPF_PROG_QUERY)): New function.
(SYS_FUNC(bpf)) <bpf_cmd_decoders>: Add BPF_PROG_QUERY entry.
(SYS_FUNC(bpf)): Fetch buf on entering and exiting, pass buf on exiting,
retrieve private data on exiting, pass it to decoder as well, explicitly
rework rc handling logic for size argument printing.
* bpf_attr.h (struct BPF_PROG_QUERY_struct): New structure declaration.
(BPF_PROG_QUERY_struct_size, expected_BPF_PROG_QUERY_struct_size): New
macro.
* tests/bpf.c: Add checks for BPF_PROG_QUERY command.
This commit is contained in:
Eugene Syromyatnikov 2018-03-01 23:54:00 +01:00 committed by Dmitry V. Levin
parent 459ea39686
commit 39f61ef513
5 changed files with 152 additions and 21 deletions

97
bpf.c
View File

@ -45,13 +45,21 @@
#include "xlat/bpf_map_update_elem_flags.h"
#include "xlat/bpf_attach_type.h"
#include "xlat/bpf_attach_flags.h"
#include "xlat/bpf_query_flags.h"
/** Storage for all the data that is needed to be stored on entering. */
struct bpf_priv_data {
bool bpf_prog_query_stored;
uint32_t bpf_prog_query_prog_cnt;
};
#define DECL_BPF_CMD_DECODER(bpf_cmd_decoder) \
int \
bpf_cmd_decoder(struct tcb *const tcp, \
const kernel_ulong_t addr, \
const unsigned int size, \
void *const data) \
void *const data, \
struct bpf_priv_data *priv) \
/* End of DECL_BPF_CMD_DECODER definition. */
#define BEGIN_BPF_CMD_DECODER(bpf_cmd) \
@ -313,6 +321,53 @@ BEGIN_BPF_CMD_DECODER(BPF_OBJ_GET_INFO_BY_FD)
}
END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
BEGIN_BPF_CMD_DECODER(BPF_PROG_QUERY)
{
uint64_t prog_id_buf;
if (entering(tcp)) {
PRINT_FIELD_FD("{query={", attr, target_fd, tcp);
PRINT_FIELD_XVAL(", ", attr, attach_type, bpf_attach_type,
"BPF_???");
PRINT_FIELD_FLAGS(", ", attr, query_flags, bpf_query_flags,
"BPF_F_QUERY_???");
PRINT_FIELD_FLAGS(", ", attr, attach_flags, bpf_attach_flags,
"BPF_F_???");
tprints(", prog_ids=");
if (!priv)
priv = xcalloc(1, sizeof(*priv));
priv->bpf_prog_query_stored = true;
priv->bpf_prog_query_prog_cnt = attr.prog_cnt;
set_tcb_priv_data(tcp, priv, free);
return 0;
}
/*
* The issue here is that we can't pass pointers bigger than
* (our) kernel long ti print_array, so we opt out from decoding
* the array.
*/
if (syserror(tcp) || attr.prog_ids > max_kaddr())
printaddr64(attr.prog_ids);
else
print_array(tcp, attr.prog_ids, attr.prog_cnt, &prog_id_buf,
sizeof(prog_id_buf), umoven_or_printaddr,
print_uint64_array_member, 0);
tprints(", prog_cnt=");
if (priv && priv->bpf_prog_query_stored
&& priv->bpf_prog_query_prog_cnt != attr.prog_cnt)
tprintf("%" PRIu32 " => ", priv->bpf_prog_query_prog_cnt);
tprintf("%" PRIu32, attr.prog_cnt);
tprints("}");
}
END_BPF_CMD_DECODER(RVAL_DECODED)
SYS_FUNC(bpf)
{
static const bpf_cmd_decoder_t bpf_cmd_decoders[] = {
@ -332,38 +387,38 @@ SYS_FUNC(bpf)
BPF_CMD_ENTRY(BPF_PROG_GET_FD_BY_ID),
BPF_CMD_ENTRY(BPF_MAP_GET_FD_BY_ID),
BPF_CMD_ENTRY(BPF_OBJ_GET_INFO_BY_FD),
BPF_CMD_ENTRY(BPF_PROG_QUERY),
};
static char *buf;
struct bpf_priv_data *priv = NULL;
const unsigned int cmd = tcp->u_arg[0];
const kernel_ulong_t addr = tcp->u_arg[1];
const unsigned int size = tcp->u_arg[2];
int rc;
int rc = RVAL_DECODED;
if (!buf)
buf = xmalloc(get_pagesize());
if (entering(tcp)) {
static char *buf;
if (!buf)
buf = xmalloc(get_pagesize());
printxval(bpf_commands, cmd, "BPF_???");
tprints(", ");
if (size > 0
&& size <= get_pagesize()
&& cmd < ARRAY_SIZE(bpf_cmd_decoders)
&& bpf_cmd_decoders[cmd]) {
rc = umoven_or_printaddr(tcp, addr, size, buf)
? RVAL_DECODED
: bpf_cmd_decoders[cmd](tcp, addr, size, buf);
} else {
printaddr(addr);
rc = RVAL_DECODED;
}
} else {
rc = bpf_cmd_decoders[cmd](tcp, addr, size, NULL) | RVAL_DECODED;
priv = get_tcb_priv_data(tcp);
}
if (rc & RVAL_DECODED)
if (size > 0
&& size <= get_pagesize()
&& cmd < ARRAY_SIZE(bpf_cmd_decoders)
&& bpf_cmd_decoders[cmd]) {
if (!umoven_or_printaddr_ignore_syserror(tcp, addr, size, buf))
rc = bpf_cmd_decoders[cmd](tcp, addr, size, buf, priv);
} else {
printaddr(addr);
}
if (exiting(tcp) || (rc & RVAL_DECODED))
tprintf(", %u", size);
return rc;

View File

@ -200,4 +200,17 @@ struct BPF_OBJ_GET_INFO_BY_FD_struct /* info */ {
sizeof(struct BPF_OBJ_GET_INFO_BY_FD_struct)
#define expected_BPF_OBJ_GET_INFO_BY_FD_struct_size 16
struct BPF_PROG_QUERY_struct /* query */ {
uint32_t target_fd;
uint32_t attach_type;
uint32_t query_flags;
uint32_t attach_flags;
uint64_t ATTRIBUTE_ALIGNED(8) prog_ids;
uint32_t prog_cnt;
};
#define BPF_PROG_QUERY_struct_size \
offsetofend(struct BPF_PROG_QUERY_struct, prog_cnt)
#define expected_BPF_PROG_QUERY_struct_size 28
#endif /* !STRACE_BPF_ATTR_H */

View File

@ -76,6 +76,7 @@ union bpf_attr_data {
BPF_ATTR_DATA_FIELD(BPF_PROG_GET_FD_BY_ID);
BPF_ATTR_DATA_FIELD(BPF_MAP_GET_FD_BY_ID);
BPF_ATTR_DATA_FIELD(BPF_OBJ_GET_INFO_BY_FD);
BPF_ATTR_DATA_FIELD(BPF_PROG_QUERY);
char char_data[256];
};
@ -697,6 +698,65 @@ static const struct bpf_attr_check BPF_OBJ_GET_INFO_BY_FD_checks[] = {
}
};
/* TODO: This is a read/write cmd and we do not check exiting path yet */
static const struct bpf_attr_check BPF_PROG_QUERY_checks[] = {
{
.data = { .BPF_PROG_QUERY_data = { .target_fd = -1 } },
.size = offsetofend(struct BPF_PROG_QUERY_struct, target_fd),
.str = "query={target_fd=-1"
", attach_type=BPF_CGROUP_INET_INGRESS, query_flags=0"
", attach_flags=0, prog_ids=NULL, prog_cnt=0}",
},
{ /* 1 */
.data = { .BPF_PROG_QUERY_data = {
.target_fd = 3141592653U,
.attach_type = 6,
.query_flags = 1,
.attach_flags = 3,
} },
.size = offsetofend(struct BPF_PROG_QUERY_struct, attach_flags),
.str = "query={target_fd=-1153374643"
", attach_type=BPF_CGROUP_DEVICE"
", query_flags=BPF_F_QUERY_EFFECTIVE"
", attach_flags=BPF_F_ALLOW_OVERRIDE|BPF_F_ALLOW_MULTI"
", prog_ids=NULL, prog_cnt=0}",
},
{ /* 2 */
.data = { .BPF_PROG_QUERY_data = {
.target_fd = 3141592653U,
.attach_type = 7,
.query_flags = 0xfffffffe,
.attach_flags = 0xfffffffc,
.prog_ids = 0xffffffffffffffffULL,
.prog_cnt = 2718281828,
} },
.size = offsetofend(struct BPF_PROG_QUERY_struct, prog_cnt),
.str = "query={target_fd=-1153374643"
", attach_type=0x7 /* BPF_??? */"
", query_flags=0xfffffffe /* BPF_F_QUERY_??? */"
", attach_flags=0xfffffffc /* BPF_F_??? */"
", prog_ids=0xffffffffffffffff, prog_cnt=2718281828}",
},
{ /* 3 */
.data = { .BPF_PROG_QUERY_data = {
.target_fd = 3141592653U,
.attach_type = 0xfeedface,
.query_flags = 0xdeadf00d,
.attach_flags = 0xbeefcafe,
.prog_ids = 0xffffffffffffffffULL,
.prog_cnt = 0,
} },
.size = offsetofend(struct BPF_PROG_QUERY_struct, prog_cnt),
.str = "query={target_fd=-1153374643"
", attach_type=0xfeedface /* BPF_??? */"
", query_flags=BPF_F_QUERY_EFFECTIVE|0xdeadf00c"
", attach_flags=BPF_F_ALLOW_MULTI|0xbeefcafc"
", prog_ids=0xffffffffffffffff, prog_cnt=0}",
},
};
#define CHK(cmd_) \
{ \
cmd_, #cmd_, \
@ -724,6 +784,7 @@ main(void)
CHK(BPF_PROG_GET_FD_BY_ID),
CHK(BPF_MAP_GET_FD_BY_ID),
CHK(BPF_OBJ_GET_INFO_BY_FD),
CHK(BPF_PROG_QUERY),
};
page_size = get_page_size();

View File

@ -14,3 +14,4 @@ BPF_MAP_GET_NEXT_ID 12
BPF_PROG_GET_FD_BY_ID 13
BPF_MAP_GET_FD_BY_ID 14
BPF_OBJ_GET_INFO_BY_FD 15
BPF_PROG_QUERY 16

1
xlat/bpf_query_flags.in Normal file
View File

@ -0,0 +1 @@
BPF_F_QUERY_EFFECTIVE (1U << 0)