Skip to content

Commit ddb53dd

Browse files
committed
Implement bpf syscall decoding
* bpf.c: New file. * Makefile.am (strace_SOURCES): Add it. * configure.ac (AC_CHECK_HEADERS): Add linux/bpf.h. * linux/dummy.h (sys_bpf): Remove. * pathtrace.c (pathtrace_match): Add SEN_bpf. * xlat/bpf_commands.in: New file. * xlat/bpf_map_types.in: New file. * xlat/bpf_map_update_elem_flags.in: New file. * xlat/bpf_prog_types.in: New file. * tests/bpf.c: New file. * tests/bpf.test: New test. * tests/Makefile.am (check_PROGRAMS): Add bpf. (TESTS): Add bpf.test. * tests/.gitignore: Add bpf.
1 parent 3691562 commit ddb53dd

File tree

13 files changed

+361
-1
lines changed

13 files changed

+361
-1
lines changed

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ strace_SOURCES = \
3131
aio.c \
3232
bjm.c \
3333
block.c \
34+
bpf.c \
3435
cacheflush.c \
3536
capability.c \
3637
caps0.h \

bpf.c

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/*
2+
* Copyright (c) 2015 Dmitry V. Levin <[email protected]>
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions
7+
* are met:
8+
* 1. Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* 2. Redistributions in binary form must reproduce the above copyright
11+
* notice, this list of conditions and the following disclaimer in the
12+
* documentation and/or other materials provided with the distribution.
13+
* 3. The name of the author may not be used to endorse or promote products
14+
* derived from this software without specific prior written permission.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19+
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*/
27+
28+
#include "defs.h"
29+
30+
#ifdef HAVE_LINUX_BPF_H
31+
# include <linux/bpf.h>
32+
#endif
33+
34+
#include "xlat/bpf_commands.h"
35+
#include "xlat/bpf_map_types.h"
36+
#include "xlat/bpf_prog_types.h"
37+
#include "xlat/bpf_map_update_elem_flags.h"
38+
39+
static int
40+
bpf_map_create(struct tcb *tcp, const long addr, unsigned int size)
41+
{
42+
struct {
43+
uint32_t map_type, key_size, value_size, max_entries;
44+
} attr = {};
45+
46+
if (!size) {
47+
printaddr(addr);
48+
return RVAL_DECODED | RVAL_FD;
49+
}
50+
if (size > sizeof(attr))
51+
size = sizeof(attr);
52+
if (umoven_or_printaddr(tcp, addr, size, &attr))
53+
return RVAL_DECODED | RVAL_FD;
54+
55+
tprints("{map_type=");
56+
printxval(bpf_map_types, attr.map_type, "BPF_MAP_TYPE_???");
57+
tprintf(", key_size=%u, value_size=%u, max_entries=%u}",
58+
attr.key_size, attr.value_size, attr.max_entries);
59+
60+
return RVAL_DECODED | RVAL_FD;
61+
}
62+
63+
static void
64+
bpf_map_update_elem(struct tcb *tcp, const long addr, unsigned int size)
65+
{
66+
struct {
67+
uint32_t map_fd;
68+
uint64_t ATTRIBUTE_ALIGNED(8) key;
69+
uint64_t ATTRIBUTE_ALIGNED(8) value;
70+
uint64_t flags;
71+
} attr = {};
72+
73+
if (!size) {
74+
printaddr(addr);
75+
return;
76+
}
77+
if (size > sizeof(attr))
78+
size = sizeof(attr);
79+
if (umoven_or_printaddr(tcp, addr, size, &attr))
80+
return;
81+
82+
tprints("{map_fd=");
83+
printfd(tcp, attr.map_fd);
84+
tprintf(", key=%#" PRIx64 ", value=%#" PRIx64 ", flags=",
85+
attr.key, attr.value);
86+
printxval(bpf_map_update_elem_flags, attr.flags, "BPF_???");
87+
tprints("}");
88+
}
89+
90+
static void
91+
bpf_map_delete_elem(struct tcb *tcp, const long addr, unsigned int size)
92+
{
93+
struct {
94+
uint32_t map_fd;
95+
uint64_t ATTRIBUTE_ALIGNED(8) key;
96+
} attr = {};
97+
98+
if (!size) {
99+
printaddr(addr);
100+
return;
101+
}
102+
if (size > sizeof(attr))
103+
size = sizeof(attr);
104+
if (umoven_or_printaddr(tcp, addr, size, &attr))
105+
return;
106+
107+
tprints("{map_fd=");
108+
printfd(tcp, attr.map_fd);
109+
tprintf(", key=%#" PRIx64 "}", attr.key);
110+
}
111+
112+
static int
113+
bpf_map_io(struct tcb *tcp, const long addr, unsigned int size, const char *text)
114+
{
115+
struct bpf_io_elem_struct {
116+
uint32_t map_fd;
117+
uint64_t ATTRIBUTE_ALIGNED(8) key;
118+
uint64_t ATTRIBUTE_ALIGNED(8) value;
119+
} attr = {};
120+
121+
if (exiting(tcp)) {
122+
if (!syserror(tcp) && !umove_or_printaddr(tcp, addr, &attr))
123+
tprintf(", %s=%#" PRIx64, text, attr.value);
124+
tprints("}");
125+
return RVAL_DECODED;
126+
}
127+
128+
if (!size) {
129+
printaddr(addr);
130+
return RVAL_DECODED;
131+
}
132+
if (size > sizeof(attr))
133+
size = sizeof(attr);
134+
if (umoven_or_printaddr(tcp, addr, size, &attr))
135+
return RVAL_DECODED;
136+
137+
tprints("{map_fd=");
138+
printfd(tcp, attr.map_fd);
139+
tprintf(", key=%#" PRIx64, attr.key);
140+
141+
return 0;
142+
}
143+
144+
static int
145+
bpf_prog_load(struct tcb *tcp, const long addr, unsigned int size)
146+
{
147+
struct {
148+
uint32_t prog_type, insn_cnt;
149+
uint64_t ATTRIBUTE_ALIGNED(8) insns, license;
150+
uint32_t log_level, log_size;
151+
uint64_t ATTRIBUTE_ALIGNED(8) log_buf;
152+
uint32_t kern_version;
153+
} attr = {};
154+
155+
if (!size) {
156+
printaddr(addr);
157+
return RVAL_DECODED | RVAL_FD;
158+
}
159+
if (size > sizeof(attr))
160+
size = sizeof(attr);
161+
if (umoven_or_printaddr(tcp, addr, size, &attr))
162+
return RVAL_DECODED | RVAL_FD;
163+
164+
tprints("{prog_type=");
165+
printxval(bpf_prog_types, attr.prog_type, "BPF_PROG_TYPE_???");
166+
tprintf(", insn_cnt=%u, insns=%#" PRIx64 ", license=",
167+
attr.insn_cnt, attr.insns);
168+
printstr(tcp, attr.license, -1);
169+
tprintf(", log_level=%u, log_size=%u, log_buf=%#" PRIx64 ", kern_version=%u}",
170+
attr.log_level, attr.log_size, attr.log_buf, attr.kern_version);
171+
172+
return RVAL_DECODED | RVAL_FD;
173+
}
174+
175+
SYS_FUNC(bpf)
176+
{
177+
const int cmd = tcp->u_arg[0];
178+
const long addr = tcp->u_arg[1];
179+
const unsigned int size = tcp->u_arg[2];
180+
int rc = RVAL_DECODED;
181+
182+
if (entering(tcp)) {
183+
printxval(bpf_commands, cmd, "BPF_???");
184+
tprints(", ");
185+
}
186+
187+
switch (cmd) {
188+
case BPF_MAP_CREATE:
189+
rc = bpf_map_create(tcp, addr, size);
190+
break;
191+
case BPF_MAP_LOOKUP_ELEM:
192+
rc = bpf_map_io(tcp, addr, size, "value");
193+
break;
194+
case BPF_MAP_UPDATE_ELEM:
195+
bpf_map_update_elem(tcp, addr, size);
196+
break;
197+
case BPF_MAP_DELETE_ELEM:
198+
bpf_map_delete_elem(tcp, addr, size);
199+
break;
200+
case BPF_MAP_GET_NEXT_KEY:
201+
rc = bpf_map_io(tcp, addr, size, "next_key");
202+
break;
203+
case BPF_PROG_LOAD:
204+
rc = bpf_prog_load(tcp, addr, size);
205+
break;
206+
default:
207+
printaddr(addr);
208+
break;
209+
}
210+
211+
if (rc & RVAL_DECODED)
212+
tprintf(", %u", size);
213+
214+
return rc;
215+
}

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ AC_CHECK_HEADERS(m4_normalize([
253253
elf.h
254254
inttypes.h
255255
ioctls.h
256+
linux/bpf.h
256257
linux/bsg.h
257258
linux/falloc.h
258259
linux/filter.h

linux/dummy.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#endif
3333

3434
/* still unfinished */
35-
#define sys_bpf printargs
3635
#define sys_execveat printargs
3736
#define sys_ioperm printargs
3837
#define sys_iopl printargs

pathtrace.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ pathtrace_match(struct tcb *tcp)
318318
return 0;
319319
}
320320

321+
case SEN_bpf:
321322
case SEN_epoll_create:
322323
case SEN_eventfd2:
323324
case SEN_eventfd:

tests/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
bpf
12
caps
23
fanotify_mark
34
filter-unavailable

tests/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ AM_CPPFLAGS = -I$(top_builddir)/$(OS)/$(ARCH) \
99
-I$(top_srcdir)/$(OS)
1010

1111
check_PROGRAMS = \
12+
bpf \
1213
caps \
1314
fanotify_mark \
1415
filter-unavailable \
@@ -61,6 +62,7 @@ TESTS = \
6162
strace-f.test \
6263
qual_syscall.test \
6364
bexecve.test \
65+
bpf.test \
6466
caps.test \
6567
dumpio.test \
6668
fanotify_mark.test \

tests/bpf.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#ifdef HAVE_CONFIG_H
2+
# include "config.h"
3+
#endif
4+
5+
#include <stdio.h>
6+
#include <stdint.h>
7+
#include <unistd.h>
8+
#include <sys/syscall.h>
9+
10+
#if defined HAVE_LINUX_BPF_H && defined __NR_bpf
11+
# include <linux/bpf.h>
12+
13+
static const struct bpf_insn insns[] = {
14+
{ .code = BPF_JMP | BPF_EXIT }
15+
};
16+
17+
static char log_buf[4096];
18+
19+
static int
20+
map_create(void)
21+
{
22+
union bpf_attr attr = {
23+
.key_size = 4,
24+
.value_size = 8,
25+
.max_entries = 256
26+
};
27+
return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
28+
}
29+
30+
static int
31+
map_any(int cmd)
32+
{
33+
union bpf_attr attr = {
34+
.map_fd = -1,
35+
.key = 0xdeadbeef,
36+
.value = 0xbadc0ded
37+
};
38+
return syscall(__NR_bpf, cmd, &attr, sizeof(attr));
39+
}
40+
41+
static int
42+
prog_load(void)
43+
{
44+
union bpf_attr attr = {
45+
.insn_cnt = sizeof(insns) / sizeof(insns[0]),
46+
.insns = (unsigned long) insns,
47+
.license = (unsigned long) "GPL",
48+
.log_level = 42,
49+
.log_size = sizeof(log_buf),
50+
.log_buf = (unsigned long) log_buf
51+
};
52+
return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
53+
}
54+
55+
int
56+
main(void)
57+
{
58+
if (!map_create())
59+
return 77;
60+
printf("bpf\\(BPF_MAP_CREATE, "
61+
"\\{map_type=BPF_MAP_TYPE_UNSPEC, key_size=4, value_size=8, max_entries=256\\}, "
62+
"%u\\) += -1 .*\n",
63+
(unsigned) sizeof(union bpf_attr));
64+
65+
if (!map_any(BPF_MAP_LOOKUP_ELEM))
66+
return 77;
67+
printf("bpf\\(BPF_MAP_LOOKUP_ELEM, "
68+
"\\{map_fd=-1, key=0xdeadbeef\\}, %u\\) += -1 .*\n",
69+
(unsigned) sizeof(union bpf_attr));
70+
71+
if (!map_any(BPF_MAP_UPDATE_ELEM))
72+
return 77;
73+
printf("bpf\\(BPF_MAP_UPDATE_ELEM, "
74+
"\\{map_fd=-1, key=0xdeadbeef, value=0xbadc0ded, flags=BPF_ANY\\}, "
75+
"%u\\) += -1 .*\n",
76+
(unsigned) sizeof(union bpf_attr));
77+
78+
if (!map_any(BPF_MAP_DELETE_ELEM))
79+
return 77;
80+
printf("bpf\\(BPF_MAP_DELETE_ELEM, "
81+
"\\{map_fd=-1, key=0xdeadbeef\\}, %u\\) += -1 .*\n",
82+
(unsigned) sizeof(union bpf_attr));
83+
84+
if (!map_any(BPF_MAP_GET_NEXT_KEY))
85+
return 77;
86+
printf("bpf\\(BPF_MAP_GET_NEXT_KEY, "
87+
"\\{map_fd=-1, key=0xdeadbeef\\}, %u\\) += -1 .*\n",
88+
(unsigned) sizeof(union bpf_attr));
89+
90+
if (!prog_load())
91+
return 77;
92+
printf("bpf\\(BPF_PROG_LOAD, "
93+
"\\{prog_type=BPF_PROG_TYPE_UNSPEC, insn_cnt=1, insns=%p, "
94+
"license=\"GPL\", log_level=42, log_size=4096, log_buf=%p, "
95+
"kern_version=0\\}, %u\\) += -1 .*\n",
96+
insns, log_buf, (unsigned) sizeof(union bpf_attr));
97+
98+
return 0;
99+
}
100+
101+
#else
102+
103+
int
104+
main(void)
105+
{
106+
return 77;
107+
}
108+
109+
#endif

tests/bpf.test

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/sh
2+
3+
# Check bpf syscall decoding.
4+
5+
. "${srcdir=.}/init.sh"
6+
7+
run_prog > /dev/null
8+
OUT="$LOG.out"
9+
run_strace -ebpf $args > "$OUT"
10+
match_grep "$LOG" "$OUT"
11+
rm -f "$OUT"
12+
13+
exit 0

xlat/bpf_commands.in

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
BPF_MAP_CREATE 0
2+
BPF_MAP_LOOKUP_ELEM 1
3+
BPF_MAP_UPDATE_ELEM 2
4+
BPF_MAP_DELETE_ELEM 3
5+
BPF_MAP_GET_NEXT_KEY 4
6+
BPF_PROG_LOAD 5

0 commit comments

Comments
 (0)