You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
|
|
1
(2) |
2
(1) |
3
|
4
|
|
5
|
6
(2) |
7
(1) |
8
|
9
(1) |
10
(1) |
11
(2) |
|
12
(1) |
13
(3) |
14
(5) |
15
|
16
|
17
(4) |
18
|
|
19
(4) |
20
|
21
|
22
|
23
(2) |
24
(1) |
25
|
|
26
|
27
|
28
|
29
|
30
|
31
|
|
|
From: Tom H. <tom...@so...> - 2018-08-14 19:48:50
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=488a5b8bb62765356a01302f0d98fc1bc9d89033 commit 488a5b8bb62765356a01302f0d98fc1bc9d89033 Author: Tom Hughes <to...@co...> Date: Tue Aug 14 20:46:22 2018 +0100 Improve bpf wrapper to check arguments more carefully Diff: --- coregrind/m_syswrap/syswrap-linux.c | 245 +++++++++++++++++++++--------------- include/vki/vki-linux.h | 47 ++++++- 2 files changed, 192 insertions(+), 100 deletions(-) diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c index 63730b0..2c96fed 100644 --- a/coregrind/m_syswrap/syswrap-linux.c +++ b/coregrind/m_syswrap/syswrap-linux.c @@ -11649,34 +11649,59 @@ static UInt bpf_obj_get_info_size(Int fd) PRE(sys_bpf) { union vki_bpf_attr *attr = (union vki_bpf_attr *)(Addr)ARG2; - UInt res, key_size, value_size, size; + UInt res, key_size, value_size; + PRINT("sys_bpf ( %ld, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", + ARG1, ARG2, ARG3); PRE_REG_READ3(long, "bpf", int, cmd, union vki_bpf_attr *, attr, unsigned int, size); - PRINT("bpf ( %ld, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", - ARG1, ARG2, ARG3); - size = *(UInt *)(Addr)ARG3; switch (ARG1) { case VKI_BPF_PROG_GET_NEXT_ID: case VKI_BPF_MAP_GET_NEXT_ID: + PRE_MEM_WRITE("bpf(attr->next_id", (Addr)&attr->next_id, sizeof(attr->next_id)); + break; case VKI_BPF_PROG_GET_FD_BY_ID: + PRE_MEM_READ("bpf(attr->prog_id", (Addr)&attr->prog_id, sizeof(attr->prog_id)); + break; case VKI_BPF_MAP_GET_FD_BY_ID: + PRE_MEM_READ("bpf(attr->map_id", (Addr)&attr->map_id, sizeof(attr->map_id)); + break; case VKI_BPF_BTF_GET_FD_BY_ID: + PRE_MEM_READ("bpf(attr->btf_id", (Addr)&attr->btf_id, sizeof(attr->btf_id)); break; case VKI_BPF_MAP_CREATE: - if (!ML_(safe_to_deref)(attr, ARG3)) { - SET_STATUS_Failure(VKI_EINVAL); - break; - } + PRE_MEM_READ("bpf(attr->map_flags", (Addr)&attr->map_flags, sizeof(attr->map_flags)); + if (attr->map_flags & VKI_BPF_F_NUMA_NODE) + PRE_MEM_READ("bpf(attr->numa_node", (Addr)&attr->numa_node, sizeof(attr->numa_node)); + PRE_MEM_READ("bpf(attr->map_type", (Addr)&attr->map_type, sizeof(attr->map_type)); + PRE_MEM_READ("bpf(attr->map_ifindex", (Addr)&attr->map_ifindex, sizeof(attr->map_ifindex)); + PRE_MEM_READ("bpf(attr->max_entries", (Addr)&attr->max_entries, sizeof(attr->max_entries)); + PRE_MEM_READ("bpf(attr->key_size", (Addr)&attr->key_size, sizeof(attr->key_size)); + PRE_MEM_READ("bpf(attr->value_size", (Addr)&attr->value_size, sizeof(attr->value_size)); + pre_asciiz_str(tid, (unsigned long int)attr->map_name, + VKI_BPF_OBJ_NAME_LEN, "bpf(attr->map_name)"); switch (attr->map_type) { case VKI_BPF_MAP_TYPE_ARRAY_OF_MAPS: case VKI_BPF_MAP_TYPE_HASH_OF_MAPS: + PRE_MEM_READ("bpf(attr->inner_map_fd", (Addr)&attr->inner_map_fd, sizeof(attr->inner_map_fd)); if (!ML_(fd_allowed)(attr->inner_map_fd, "bpf", tid, False)) SET_STATUS_Failure(VKI_EBADF); break; + case VKI_BPF_MAP_TYPE_ARRAY: + if (ARG3 >= offsetof(union vki_bpf_attr, btf_value_type_id) + sizeof(__vki_u32)) { + PRE_MEM_READ("bpf(attr->btf_key_type_id", (Addr)&attr->btf_key_type_id, sizeof(attr->btf_key_type_id)); + PRE_MEM_READ("bpf(attr->btf_value_type_id", (Addr)&attr->btf_value_type_id, sizeof(attr->btf_value_type_id)); + if (attr->btf_key_type_id && attr->btf_value_type_id) { + PRE_MEM_READ("bpf(attr->btf_id", (Addr)&attr->btf_id, sizeof(attr->btf_id)); + if (!ML_(fd_allowed)(attr->btf_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } + } + } + break; case VKI_BPF_MAP_TYPE_UNSPEC: case VKI_BPF_MAP_TYPE_HASH: - case VKI_BPF_MAP_TYPE_ARRAY: case VKI_BPF_MAP_TYPE_PROG_ARRAY: case VKI_BPF_MAP_TYPE_PERF_EVENT_ARRAY: case VKI_BPF_MAP_TYPE_PERCPU_HASH: @@ -11694,28 +11719,13 @@ PRE(sys_bpf) default: break; } - /* - * For kernels recent enough (4.18+) to have BTF support, deal with - * BTF info. Kernel only uses the file descriptor for map types that - * support BTF information (see bpf_map_support_seq_show() in kernel), - * but we do not have a way to probe that. Let's hope that - * attr->btf_key_type_id and attr->btf_value_type_id will remain NULL - * if BTF info is not needed. - */ - if (size >= offsetof(union vki_bpf_attr, btf_value_type_id) + - sizeof(__vki_u32)) { - if (attr->btf_key_type_id && attr->btf_value_type_id) { - if (!ML_(fd_allowed)(attr->btf_fd, "bpf", tid, False)) { - SET_STATUS_Failure(VKI_EBADF); - break; - } - } - } break; case VKI_BPF_MAP_LOOKUP_ELEM: /* Perform a lookup on an eBPF map. Read key, write value. */ - if (ML_(safe_to_deref)(attr, ARG3) && - attr->key != 0 && attr->value != 0) { + PRE_MEM_READ("bpf(attr->key)", (Addr)&attr->key, sizeof(attr->key)); + PRE_MEM_READ("bpf(attr->value)", (Addr)&attr->value, sizeof(attr->value)); + PRE_MEM_READ("bpf(attr->map_fd)", (Addr)&attr->map_fd, sizeof(attr->map_fd)); + if (ML_(safe_to_deref)(attr, ARG3)) { if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) { SET_STATUS_Failure(VKI_EBADF); break; @@ -11729,8 +11739,11 @@ PRE(sys_bpf) break; case VKI_BPF_MAP_UPDATE_ELEM: /* Add or update a map element in kernel. Read key, read value. */ - if (ML_(safe_to_deref)(attr, ARG3) && - attr->key != 0 && attr->value != 0) { + PRE_MEM_READ("bpf(attr->key)", (Addr)&attr->key, sizeof(attr->key)); + PRE_MEM_READ("bpf(attr->value)", (Addr)&attr->value, sizeof(attr->value)); + PRE_MEM_READ("bpf(attr->map_fd)", (Addr)&attr->map_fd, sizeof(attr->map_fd)); + PRE_MEM_READ("bpf(attr->flags)", (Addr)&attr->flags, sizeof(attr->flags)); + if (ML_(safe_to_deref)(attr, ARG3)) { if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) { SET_STATUS_Failure(VKI_EBADF); break; @@ -11744,7 +11757,9 @@ PRE(sys_bpf) break; case VKI_BPF_MAP_DELETE_ELEM: /* Delete a map element in kernel. Read key from user space. */ - if (ML_(safe_to_deref)(attr, ARG3) && attr->key != 0) { + PRE_MEM_READ("bpf(attr->key)", (Addr)&attr->key, sizeof(attr->key)); + PRE_MEM_READ("bpf(attr->map_fd)", (Addr)&attr->map_fd, sizeof(attr->map_fd)); + if (ML_(safe_to_deref)(attr, ARG3)) { if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) { SET_STATUS_Failure(VKI_EBADF); break; @@ -11756,8 +11771,11 @@ PRE(sys_bpf) break; case VKI_BPF_MAP_GET_NEXT_KEY: /* From a key, get next key for the map. Read key, write next key. */ - if (ML_(safe_to_deref)(attr, ARG3) && - attr->key != 0 && attr->next_key != 0) { + PRE_MEM_READ("bpf(attr->key)", (Addr)&attr->key, sizeof(attr->key)); + PRE_MEM_READ("bpf(attr->next_key)", (Addr)&attr->next_key, sizeof(attr->next_key)); + PRE_MEM_READ("bpf(attr->map_fd)", (Addr)&attr->map_fd, sizeof(attr->map_fd)); + PRE_MEM_READ("bpf(attr->flags)", (Addr)&attr->flags, sizeof(attr->flags)); + if (ML_(safe_to_deref)(attr, ARG3)) { if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) { SET_STATUS_Failure(VKI_EBADF); break; @@ -11771,18 +11789,27 @@ PRE(sys_bpf) break; case VKI_BPF_PROG_LOAD: /* Load a program into the kernel from an array of instructions. */ + PRE_MEM_READ("bpf(attr->prog_type)", (Addr)&attr->prog_type, sizeof(attr->prog_type)); + PRE_MEM_READ("bpf(attr->prog_flags)", (Addr)&attr->prog_flags, sizeof(attr->prog_flags)); + PRE_MEM_READ("bpf(attr->license)", (Addr)&attr->license, sizeof(attr->license)); + PRE_MEM_READ("bpf(attr->insn_cnt)", (Addr)&attr->insn_cnt, sizeof(attr->insn_cnt)); + PRE_MEM_READ("bpf(attr->expected_attach_type)", (Addr)&attr->expected_attach_type, sizeof(attr->expected_attach_type)); + PRE_MEM_READ("bpf(attr->prog_ifindex)", (Addr)&attr->prog_ifindex, sizeof(attr->prog_ifindex)); + PRE_MEM_READ("bpf(attr->log_level)", (Addr)&attr->log_level, sizeof(attr->log_level)); + PRE_MEM_READ("bpf(attr->log_buf)", (Addr)&attr->log_buf, sizeof(attr->log_buf)); + PRE_MEM_READ("bpf(attr->log_size)", (Addr)&attr->log_size, sizeof(attr->log_size)); + pre_asciiz_str(tid, (Addr)attr->prog_name, VKI_BPF_OBJ_NAME_LEN, "bpf(attr->prog_name)"); if (ML_(safe_to_deref)(attr, ARG3)) { + if (attr->prog_type == VKI_BPF_PROG_TYPE_KPROBE) + PRE_MEM_READ("bpf(attr->kern_version)", (Addr)&attr->kern_version, sizeof(attr->kern_version)); /* Read instructions, license, program name. */ PRE_MEM_READ("bpf(attr->insns)", attr->insns, attr->insn_cnt * sizeof(struct vki_bpf_insn)); /* License is limited to 128 characters in kernel/bpf/syscall.c. */ pre_asciiz_str(tid, attr->license, 128, "bpf(attr->license)"); - pre_asciiz_str(tid, (unsigned long int)attr->prog_name, - VKI_BPF_OBJ_NAME_LEN, "bpf(attr->prog_name)"); /* Possibly write up to log_len into user space log buffer. */ - if (attr->log_level && attr->log_size > 128 && attr->log_buf != 0) - PRE_MEM_WRITE("bpf(attr->log_buf)", - attr->log_buf, attr->log_size); + if (attr->log_level || attr->log_size || attr->log_buf) + PRE_MEM_WRITE("bpf(attr->log_buf)", attr->log_buf, attr->log_size); } break; case VKI_BPF_OBJ_PIN: @@ -11790,78 +11817,61 @@ PRE(sys_bpf) /* fall through */ case VKI_BPF_OBJ_GET: /* Get pinned eBPF program or map. Read path name. */ + PRE_MEM_READ("bpf(attr->file_flags)", (Addr)&attr->file_flags, sizeof(attr->file_flags)); + PRE_MEM_READ("bpf(attr->pathname)", (Addr)&attr->pathname, sizeof(attr->pathname)); + PRE_MEM_READ("bpf(attr->bpf_fd)", (Addr)&attr->bpf_fd, sizeof(attr->bpf_fd)); if (ML_(safe_to_deref)(attr, ARG3)) { if (!ML_(fd_allowed)(attr->bpf_fd, "bpf", tid, False)) { SET_STATUS_Failure(VKI_EBADF); break; } - pre_asciiz_str(tid, attr->pathname, VKI_BPF_OBJ_NAME_LEN, - "bpf(attr->pathname)"); + pre_asciiz_str(tid, attr->pathname, VKI_BPF_OBJ_NAME_LEN, "bpf(attr->pathname)"); } break; + case VKI_BPF_PROG_ATTACH: case VKI_BPF_PROG_DETACH: /* Detach eBPF program from kernel attach point. */ + PRE_MEM_READ("bpf(attr->attach_type)", (Addr)&attr->attach_type, sizeof(attr->attach_type)); + PRE_MEM_READ("bpf(attr->target_fd)", (Addr)&attr->target_fd, sizeof(attr->target_fd)); if (ML_(safe_to_deref)(attr, ARG3)) { - switch (attr->attach_type) { - case VKI_BPF_SK_SKB_STREAM_PARSER: - case VKI_BPF_SK_SKB_STREAM_VERDICT: - case VKI_BPF_SK_MSG_VERDICT: - /* - * The above attach types do not use attr->attach_bpf_fd. - * Just check attr->target_fd and exit. - */ - if (!ML_(fd_allowed)(attr->target_fd, "bpf", tid, False)) - SET_STATUS_Failure(VKI_EBADF); - return; - case VKI_BPF_CGROUP_INET_INGRESS: - case VKI_BPF_CGROUP_INET_EGRESS: - case VKI_BPF_CGROUP_INET_SOCK_CREATE: - case VKI_BPF_CGROUP_SOCK_OPS: - case VKI_BPF_CGROUP_DEVICE: - case VKI_BPF_CGROUP_INET4_BIND: - case VKI_BPF_CGROUP_INET6_BIND: - case VKI_BPF_CGROUP_INET4_CONNECT: - case VKI_BPF_CGROUP_INET6_CONNECT: - case VKI_BPF_CGROUP_INET4_POST_BIND: - case VKI_BPF_CGROUP_INET6_POST_BIND: - case VKI_BPF_CGROUP_UDP4_SENDMSG: - case VKI_BPF_CGROUP_UDP6_SENDMSG: - case VKI_BPF_LIRC_MODE2: - default: - break; - } - } - /* fall through */ - case VKI_BPF_PROG_ATTACH: - /* Attach eBPF program to kernel attach point. */ - if (ML_(safe_to_deref)(attr, ARG3)) { - if (!ML_(fd_allowed)(attr->target_fd, "bpf", tid, False) || - !ML_(fd_allowed)(attr->attach_bpf_fd, "bpf", tid, False)) { + if (!ML_(fd_allowed)(attr->target_fd, "bpf", tid, False)) SET_STATUS_Failure(VKI_EBADF); - break; + if (ARG1 == VKI_BPF_PROG_ATTACH || + (attr->attach_type != VKI_BPF_SK_SKB_STREAM_PARSER && + attr->attach_type != VKI_BPF_SK_SKB_STREAM_VERDICT && + attr->attach_type != VKI_BPF_SK_MSG_VERDICT)) { + PRE_MEM_READ("bpf(attr->attach_bpf_fd)", (Addr)&attr->attach_bpf_fd, sizeof(attr->attach_bpf_fd)); + if (!ML_(fd_allowed)(attr->attach_bpf_fd, "bpf", tid, False)) + SET_STATUS_Failure(VKI_EBADF); } } break; case VKI_BPF_PROG_TEST_RUN: /* Test prog. Read data_in, write up to data_size_out to data_out. */ - if (ML_(safe_to_deref)(attr, ARG3) && - attr->test.data_in != 0 && attr->test.data_out != 0) { + PRE_MEM_READ("bpf(attr->test.prog_fd)", (Addr)&attr->test.prog_fd, sizeof(attr->test.prog_fd)); + PRE_MEM_READ("bpf(attr->test.repeat)", (Addr)&attr->test.repeat, sizeof(attr->test.repeat)); + PRE_MEM_READ("bpf(attr->test.data_size_in)", (Addr)&attr->test.data_size_in, sizeof(attr->test.data_size_in)); + PRE_MEM_READ("bpf(attr->test.data_in)", (Addr)&attr->test.data_in, sizeof(attr->test.data_in)); + PRE_MEM_READ("bpf(attr->test.data_out)", (Addr)&attr->test.data_out, sizeof(attr->test.data_out)); + PRE_MEM_WRITE("bpf(attr->test.retval)", (Addr)&attr->test.retval, sizeof(attr->test.retval)); + PRE_MEM_WRITE("bpf(attr->test.data_size_out)", (Addr)&attr->test.data_size_out, sizeof(attr->test.data_size_out)); + PRE_MEM_WRITE("bpf(attr->test.duration)", (Addr)&attr->test.duration, sizeof(attr->test.duration)); + if (ML_(safe_to_deref)(attr, ARG3)) { if (!ML_(fd_allowed)(attr->test.prog_fd, "bpf", tid, False)) { SET_STATUS_Failure(VKI_EBADF); break; } - PRE_MEM_READ("bpf(attr->test.data_in)", - attr->test.data_in, attr->test.data_size_in); - /* - * TODO: Kernel writes to data_out but we do not know the size yet. - * PRE_MEM_WRITE("bpf(attr->test.data_out)", - * attr->test.data_out, ??); - */ + PRE_MEM_READ("bpf(attr->test.data_in)", attr->test.data_in, attr->test.data_size_in); + /* should be data_size_in + VKI_XDP_PACKET_HEADROOM for VKI_BPF_PROG_TYPE_XDP */ + PRE_MEM_WRITE("bpf(attr->test.data_out)", attr->test.data_out, attr->test.data_size_in); } break; case VKI_BPF_OBJ_GET_INFO_BY_FD: /* Get info for eBPF map or program. Write info. */ - if (ML_(safe_to_deref)(attr, ARG3) && attr->info.info != 0) { + PRE_MEM_READ("bpf(attr->info.bpf_fd)", (Addr)&attr->info.bpf_fd, sizeof(attr->info.bpf_fd)); + PRE_MEM_READ("bpf(attr->info.info)", (Addr)&attr->info.info, sizeof(attr->info.info)); + PRE_MEM_READ("bpf(attr->info.info_len)", (Addr)&attr->info.info_len, sizeof(attr->info.info_len)); + if (ML_(safe_to_deref)(attr, ARG3)) { if (!ML_(fd_allowed)(attr->info.bpf_fd, "bpf", tid, False)) { SET_STATUS_Failure(VKI_EBADF); break; @@ -11874,8 +11884,9 @@ PRE(sys_bpf) else PRE_MEM_WRITE("bpf(attr->info.info)", attr->info.info, VG_MIN(attr->info.info_len, - VG_MAX(sizeof(struct vki_bpf_prog_info), - sizeof(struct vki_bpf_map_info)))); + VG_MAX(VG_MAX(sizeof(struct vki_bpf_prog_info), + sizeof(struct vki_bpf_map_info)), + sizeof(struct vki_bpf_btf_info)))); } break; case VKI_BPF_PROG_QUERY: @@ -11883,17 +11894,29 @@ PRE(sys_bpf) * Query list of eBPF program attached to cgroup. * Write array of ids (up to attr->query.prog_cnt u32-long ids). */ - if (ML_(safe_to_deref)(attr, ARG3) && attr->query.prog_ids != 0) { + PRE_MEM_READ("bpf(attr->query.query_flags)", (Addr)&attr->query.query_flags, sizeof(attr->query.query_flags)); + PRE_MEM_READ("bpf(attr->query.attach_type)", (Addr)&attr->query.attach_type, sizeof(attr->query.attach_type)); + PRE_MEM_READ("bpf(attr->query.target_fd)", (Addr)&attr->query.target_fd, sizeof(attr->query.target_fd)); + PRE_MEM_READ("bpf(attr->query.prog_cnt)", (Addr)&attr->query.prog_cnt, sizeof(attr->query.prog_cnt)); + PRE_MEM_WRITE("bpf(attr->query.attach_flags)", (Addr)&attr->query.attach_flags, sizeof(attr->query.attach_flags)); + if (ML_(safe_to_deref)(attr, ARG3)) { if (!ML_(fd_allowed)(attr->query.target_fd, "bpf", tid, False)) { SET_STATUS_Failure(VKI_EBADF); break; } - PRE_MEM_WRITE("bpf(attr->query.prog_ids)", attr->query.prog_ids, - attr->query.prog_cnt * sizeof(__vki_u32)); + if (attr->query.prog_cnt > 0) { + PRE_MEM_READ("bpf(attr->query.prog_ids)", (Addr)&attr->query.prog_ids, sizeof(attr->query.prog_ids)); + if (attr->query.prog_ids) { + PRE_MEM_WRITE("bpf(attr->query.prog_ids)", attr->query.prog_ids, + attr->query.prog_cnt * sizeof(__vki_u32)); + } + } } break; case VKI_BPF_RAW_TRACEPOINT_OPEN: /* Open raw tracepoint. Read tracepoint name. */ + PRE_MEM_READ("bpf(attr->raw_tracepoint.name)", (Addr)&attr->raw_tracepoint.name, sizeof(attr->raw_tracepoint.name)); + PRE_MEM_READ("bpf(attr->raw_tracepoint.prog_fd)", (Addr)&attr->raw_tracepoint.prog_fd, sizeof(attr->raw_tracepoint.prog_fd)); if (ML_(safe_to_deref)(attr, ARG3)) { if (!ML_(fd_allowed)(attr->raw_tracepoint.prog_fd, "bpf", tid, False)) { @@ -11907,17 +11930,30 @@ PRE(sys_bpf) break; case VKI_BPF_BTF_LOAD: /* Load BTF information about a program into the kernel. */ + PRE_MEM_READ("bpf(attr->btf)", (Addr)&attr->btf, sizeof(attr->btf)); + PRE_MEM_READ("bpf(attr->btf_size)", (Addr)&attr->btf_size, sizeof(attr->btf_size)); + PRE_MEM_READ("bpf(attr->btf_log_buf)", (Addr)&attr->btf_log_buf, sizeof(attr->btf_log_buf)); + PRE_MEM_READ("bpf(attr->btf_log_size)", (Addr)&attr->btf_log_size, sizeof(attr->btf_log_size)); + PRE_MEM_READ("bpf(attr->btf_log_level)", (Addr)&attr->btf_log_level, sizeof(attr->btf_log_level)); if (ML_(safe_to_deref)(attr, ARG3)) { /* Read BTF data. */ PRE_MEM_READ("bpf(attr->btf)", attr->btf, attr->btf_size); /* Possibly write up to btf_log_len into user space log buffer. */ - if (attr->btf_log_level && attr->btf_log_size > 128 && - attr->btf_log_buf != 0) + if (attr->btf_log_level || attr->btf_log_size || attr->btf_log_buf) PRE_MEM_WRITE("bpf(attr->btf_log_buf)", attr->btf_log_buf, attr->btf_log_size); } case VKI_BPF_TASK_FD_QUERY: /* Get info about the task. Write collected info. */ + PRE_MEM_READ("bpf(attr->task_fd_query.pid)", (Addr)&attr->task_fd_query.pid, sizeof(attr->task_fd_query.pid)); + PRE_MEM_READ("bpf(attr->task_fd_query.fd)", (Addr)&attr->task_fd_query.fd, sizeof(attr->task_fd_query.fd)); + PRE_MEM_READ("bpf(attr->task_fd_query.flags)", (Addr)&attr->task_fd_query.flags, sizeof(attr->task_fd_query.flags)); + PRE_MEM_READ("bpf(attr->task_fd_query.buf_len)", (Addr)&attr->task_fd_query.buf_len, sizeof(attr->task_fd_query.buf_len)); + PRE_MEM_READ("bpf(attr->task_fd_query.buf)", (Addr)&attr->task_fd_query.buf, sizeof(attr->task_fd_query.buf)); + PRE_MEM_WRITE("bpf(attr->task_fd_query.prog_id)", (Addr)&attr->task_fd_query.prog_id, sizeof(attr->task_fd_query.prog_id)); + PRE_MEM_WRITE("bpf(attr->task_fd_query.fd_type)", (Addr)&attr->task_fd_query.fd_type, sizeof(attr->task_fd_query.fd_type)); + PRE_MEM_WRITE("bpf(attr->task_fd_query.probe_offset)", (Addr)&attr->task_fd_query.probe_offset, sizeof(attr->task_fd_query.probe_offset)); + PRE_MEM_WRITE("bpf(attr->task_fd_query.probe_addr)", (Addr)&attr->task_fd_query.probe_addr, sizeof(attr->task_fd_query.probe_addr)); if (ML_(safe_to_deref)(attr, ARG3)) { if (!ML_(fd_allowed)(attr->task_fd_query.fd, "bpf", tid, False)) { SET_STATUS_Failure(VKI_EBADF); @@ -11947,13 +11983,15 @@ POST(sys_bpf) vg_assert(SUCCESS); switch (ARG1) { + case VKI_BPF_PROG_GET_NEXT_ID: + case VKI_BPF_MAP_GET_NEXT_ID: + POST_MEM_WRITE(attr->next_id, sizeof(attr->next_id)); + break; case VKI_BPF_MAP_UPDATE_ELEM: case VKI_BPF_MAP_DELETE_ELEM: case VKI_BPF_OBJ_PIN: case VKI_BPF_PROG_ATTACH: case VKI_BPF_PROG_DETACH: - case VKI_BPF_PROG_GET_NEXT_ID: - case VKI_BPF_MAP_GET_NEXT_ID: break; /* Following commands have bpf() return a file descriptor. */ case VKI_BPF_MAP_CREATE: @@ -11990,17 +12028,22 @@ POST(sys_bpf) } else { if (VG_(clo_track_fds)) ML_(record_fd_open_nameless)(tid, RES); - if (attr->log_level) - POST_MEM_WRITE(attr->log_buf, attr->log_size); } + if (attr->log_level || attr->log_size || attr->log_buf) + POST_MEM_WRITE(attr->log_buf, attr->log_size); break; case VKI_BPF_PROG_TEST_RUN: + POST_MEM_WRITE((Addr)&attr->test.retval, sizeof(attr->test.retval)); + POST_MEM_WRITE((Addr)&attr->test.data_size_out, sizeof(attr->test.data_size_out)); + POST_MEM_WRITE((Addr)&attr->test.duration, sizeof(attr->test.duration)); POST_MEM_WRITE(attr->test.data_out, attr->test.data_size_out); break; case VKI_BPF_OBJ_GET_INFO_BY_FD: POST_MEM_WRITE(attr->info.info, attr->info.info_len); break; case VKI_BPF_PROG_QUERY: + POST_MEM_WRITE((Addr)&attr->query.attach_flags, sizeof(attr->query.attach_flags)); + POST_MEM_WRITE((Addr)&attr->query.prog_cnt, sizeof(attr->query.prog_cnt)); if (attr->query.prog_ids) POST_MEM_WRITE(attr->query.prog_ids, attr->query.prog_cnt * sizeof(__vki_u32)); @@ -12013,12 +12056,16 @@ POST(sys_bpf) } else { if (VG_(clo_track_fds)) ML_(record_fd_open_nameless)(tid, RES); - if (attr->btf_log_level) - POST_MEM_WRITE(attr->btf_log_buf, attr->btf_log_size); } + if (attr->btf_log_level) + POST_MEM_WRITE(attr->btf_log_buf, attr->btf_log_size); break; case VKI_BPF_TASK_FD_QUERY: POST_MEM_WRITE(attr->task_fd_query.buf, attr->task_fd_query.buf_len); + POST_MEM_WRITE((Addr)&attr->task_fd_query.prog_id, sizeof(attr->task_fd_query.prog_id)); + POST_MEM_WRITE((Addr)&attr->task_fd_query.fd_type, sizeof(attr->task_fd_query.fd_type)); + POST_MEM_WRITE((Addr)&attr->task_fd_query.probe_offset, sizeof(attr->task_fd_query.probe_offset)); + POST_MEM_WRITE((Addr)&attr->task_fd_query.probe_addr, sizeof(attr->task_fd_query.probe_addr)); break; default: VG_(message)(Vg_DebugMsg, diff --git a/include/vki/vki-linux.h b/include/vki/vki-linux.h index 9ffb002..815f658 100644 --- a/include/vki/vki-linux.h +++ b/include/vki/vki-linux.h @@ -242,6 +242,8 @@ typedef __vki_u64 vki_uint64_t; typedef __vki_u16 __vki_le16; +#define __vki_aligned_u64 __vki_u64 __attribute__((aligned(8))) + //---------------------------------------------------------------------- // From linux-2.6.8.1/include/linux/limits.h //---------------------------------------------------------------------- @@ -4887,6 +4889,30 @@ enum vki_bpf_map_type { VKI_BPF_MAP_TYPE_SOCKHASH, }; +enum vki_bpf_prog_type { + VKI_BPF_PROG_TYPE_UNSPEC, + VKI_BPF_PROG_TYPE_SOCKET_FILTER, + VKI_BPF_PROG_TYPE_KPROBE, + VKI_BPF_PROG_TYPE_SCHED_CLS, + VKI_BPF_PROG_TYPE_SCHED_ACT, + VKI_BPF_PROG_TYPE_TRACEPOINT, + VKI_BPF_PROG_TYPE_XDP, + VKI_BPF_PROG_TYPE_PERF_EVENT, + VKI_BPF_PROG_TYPE_CGROUP_SKB, + VKI_BPF_PROG_TYPE_CGROUP_SOCK, + VKI_BPF_PROG_TYPE_LWT_IN, + VKI_BPF_PROG_TYPE_LWT_OUT, + VKI_BPF_PROG_TYPE_LWT_XMIT, + VKI_BPF_PROG_TYPE_SOCK_OPS, + VKI_BPF_PROG_TYPE_SK_SKB, + VKI_BPF_PROG_TYPE_CGROUP_DEVICE, + VKI_BPF_PROG_TYPE_SK_MSG, + VKI_BPF_PROG_TYPE_RAW_TRACEPOINT, + VKI_BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + VKI_BPF_PROG_TYPE_LWT_SEG6LOCAL, + VKI_BPF_PROG_TYPE_LIRC_MODE2, +}; + enum vki_bpf_attach_type { VKI_BPF_CGROUP_INET_INGRESS, VKI_BPF_CGROUP_INET_EGRESS, @@ -4908,9 +4934,11 @@ enum vki_bpf_attach_type { __VKI_MAX_BPF_ATTACH_TYPE }; +/* Specify numa node during map creation */ +#define VKI_BPF_F_NUMA_NODE (1U << 2) + #define VKI_BPF_OBJ_NAME_LEN 16U -#define __vki_aligned_u64 __vki_u64 __attribute__((aligned(8))) union vki_bpf_attr { struct { /* anonymous struct used by BPF_MAP_CREATE command */ __vki_u32 map_type; /* one of enum bpf_map_type */ @@ -5040,6 +5068,8 @@ union vki_bpf_attr { } task_fd_query; } __attribute__((aligned(8))); +#define VKI_XDP_PACKET_HEADROOM 256 + #define VKI_BPF_TAG_SIZE 8 struct vki_bpf_prog_info { @@ -5056,8 +5086,13 @@ struct vki_bpf_prog_info { __vki_aligned_u64 map_ids; char name[VKI_BPF_OBJ_NAME_LEN]; __vki_u32 ifindex; + __vki_u32 gpl_compatible:1; __vki_u64 netns_dev; __vki_u64 netns_ino; + __vki_u32 nr_jited_ksyms; + __vki_u32 nr_jited_func_lens; + __vki_aligned_u64 jited_ksyms; + __vki_aligned_u64 jited_func_lens; } __attribute__((aligned(8))); struct vki_bpf_map_info { @@ -5069,8 +5104,18 @@ struct vki_bpf_map_info { __vki_u32 map_flags; char name[VKI_BPF_OBJ_NAME_LEN]; __vki_u32 ifindex; + __vki_u32 :32; __vki_u64 netns_dev; __vki_u64 netns_ino; + __vki_u32 btf_id; + __vki_u32 btf_key_type_id; + __vki_u32 btf_value_type_id; +} __attribute__((aligned(8))); + +struct vki_bpf_btf_info { + __vki_aligned_u64 btf; + __vki_u32 btf_size; + __vki_u32 id; } __attribute__((aligned(8))); /*--------------------------------------------------------------------*/ |
|
From: Tom H. <tom...@so...> - 2018-08-14 19:48:48
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=0097176525896f377a4a0686b928e2ba570e5ad4 commit 0097176525896f377a4a0686b928e2ba570e5ad4 Author: Quentin Monnet <que...@ne...> Date: Sat Apr 14 23:56:37 2018 +0100 Add file descriptor tracking in wrappers for bpf system call Support for the bpf system call was added in a previous commit, but did not include tracking for file descriptors handled by the call. Add checks and tracking for file descriptors. Check in PRE() wrapper that all file descriptors (pointing to object such as eBPF programs or maps, cgroups, or raw tracepoints) used by the system call are valid, then add tracking in POST() wrapper for newly produced file descriptors. As the file descriptors are not always processed in the same way by the bpf call, add to the header file some additional definitions from bpf.h that are necessary to sort out under what conditions descriptors should be checked in the PRE() helper. Diff: --- coregrind/m_syswrap/syswrap-linux.c | 181 +++++++++++++++++++++++++++++++++--- include/vki/vki-linux.h | 43 +++++++++ 2 files changed, 212 insertions(+), 12 deletions(-) diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c index 1e6f5fc..63730b0 100644 --- a/coregrind/m_syswrap/syswrap-linux.c +++ b/coregrind/m_syswrap/syswrap-linux.c @@ -11649,26 +11649,77 @@ static UInt bpf_obj_get_info_size(Int fd) PRE(sys_bpf) { union vki_bpf_attr *attr = (union vki_bpf_attr *)(Addr)ARG2; - UInt res, key_size, value_size; + UInt res, key_size, value_size, size; PRE_REG_READ3(long, "bpf", int, cmd, union vki_bpf_attr *, attr, unsigned int, size); PRINT("bpf ( %ld, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3); + size = *(UInt *)(Addr)ARG3; switch (ARG1) { - case VKI_BPF_MAP_CREATE: - case VKI_BPF_PROG_ATTACH: - case VKI_BPF_PROG_DETACH: case VKI_BPF_PROG_GET_NEXT_ID: case VKI_BPF_MAP_GET_NEXT_ID: case VKI_BPF_PROG_GET_FD_BY_ID: case VKI_BPF_MAP_GET_FD_BY_ID: case VKI_BPF_BTF_GET_FD_BY_ID: break; + case VKI_BPF_MAP_CREATE: + if (!ML_(safe_to_deref)(attr, ARG3)) { + SET_STATUS_Failure(VKI_EINVAL); + break; + } + switch (attr->map_type) { + case VKI_BPF_MAP_TYPE_ARRAY_OF_MAPS: + case VKI_BPF_MAP_TYPE_HASH_OF_MAPS: + if (!ML_(fd_allowed)(attr->inner_map_fd, "bpf", tid, False)) + SET_STATUS_Failure(VKI_EBADF); + break; + case VKI_BPF_MAP_TYPE_UNSPEC: + case VKI_BPF_MAP_TYPE_HASH: + case VKI_BPF_MAP_TYPE_ARRAY: + case VKI_BPF_MAP_TYPE_PROG_ARRAY: + case VKI_BPF_MAP_TYPE_PERF_EVENT_ARRAY: + case VKI_BPF_MAP_TYPE_PERCPU_HASH: + case VKI_BPF_MAP_TYPE_PERCPU_ARRAY: + case VKI_BPF_MAP_TYPE_STACK_TRACE: + case VKI_BPF_MAP_TYPE_CGROUP_ARRAY: + case VKI_BPF_MAP_TYPE_LRU_HASH: + case VKI_BPF_MAP_TYPE_LRU_PERCPU_HASH: + case VKI_BPF_MAP_TYPE_LPM_TRIE: + case VKI_BPF_MAP_TYPE_DEVMAP: + case VKI_BPF_MAP_TYPE_SOCKMAP: + case VKI_BPF_MAP_TYPE_CPUMAP: + case VKI_BPF_MAP_TYPE_XSKMAP: + case VKI_BPF_MAP_TYPE_SOCKHASH: + default: + break; + } + /* + * For kernels recent enough (4.18+) to have BTF support, deal with + * BTF info. Kernel only uses the file descriptor for map types that + * support BTF information (see bpf_map_support_seq_show() in kernel), + * but we do not have a way to probe that. Let's hope that + * attr->btf_key_type_id and attr->btf_value_type_id will remain NULL + * if BTF info is not needed. + */ + if (size >= offsetof(union vki_bpf_attr, btf_value_type_id) + + sizeof(__vki_u32)) { + if (attr->btf_key_type_id && attr->btf_value_type_id) { + if (!ML_(fd_allowed)(attr->btf_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } + } + } + break; case VKI_BPF_MAP_LOOKUP_ELEM: /* Perform a lookup on an eBPF map. Read key, write value. */ if (ML_(safe_to_deref)(attr, ARG3) && attr->key != 0 && attr->value != 0) { + if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } /* Get size of key and value for this map. */ if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) { PRE_MEM_READ("bpf(attr->key)", attr->key, key_size); @@ -11680,6 +11731,10 @@ PRE(sys_bpf) /* Add or update a map element in kernel. Read key, read value. */ if (ML_(safe_to_deref)(attr, ARG3) && attr->key != 0 && attr->value != 0) { + if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } /* Get size of key and value for this map. */ if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) { PRE_MEM_READ("bpf(attr->key)", attr->key, key_size); @@ -11690,6 +11745,10 @@ PRE(sys_bpf) case VKI_BPF_MAP_DELETE_ELEM: /* Delete a map element in kernel. Read key from user space. */ if (ML_(safe_to_deref)(attr, ARG3) && attr->key != 0) { + if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } /* Get size of key for this map. */ if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) PRE_MEM_READ("bpf(attr->key)", attr->key, key_size); @@ -11699,6 +11758,10 @@ PRE(sys_bpf) /* From a key, get next key for the map. Read key, write next key. */ if (ML_(safe_to_deref)(attr, ARG3) && attr->key != 0 && attr->next_key != 0) { + if (!ML_(fd_allowed)(attr->map_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } /* Get size of key for this map. */ if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) { PRE_MEM_READ("bpf(attr->key)", attr->key, key_size); @@ -11727,14 +11790,66 @@ PRE(sys_bpf) /* fall through */ case VKI_BPF_OBJ_GET: /* Get pinned eBPF program or map. Read path name. */ - if (ML_(safe_to_deref)(attr, ARG3)) + if (ML_(safe_to_deref)(attr, ARG3)) { + if (!ML_(fd_allowed)(attr->bpf_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } pre_asciiz_str(tid, attr->pathname, VKI_BPF_OBJ_NAME_LEN, "bpf(attr->pathname)"); + } + break; + case VKI_BPF_PROG_DETACH: + /* Detach eBPF program from kernel attach point. */ + if (ML_(safe_to_deref)(attr, ARG3)) { + switch (attr->attach_type) { + case VKI_BPF_SK_SKB_STREAM_PARSER: + case VKI_BPF_SK_SKB_STREAM_VERDICT: + case VKI_BPF_SK_MSG_VERDICT: + /* + * The above attach types do not use attr->attach_bpf_fd. + * Just check attr->target_fd and exit. + */ + if (!ML_(fd_allowed)(attr->target_fd, "bpf", tid, False)) + SET_STATUS_Failure(VKI_EBADF); + return; + case VKI_BPF_CGROUP_INET_INGRESS: + case VKI_BPF_CGROUP_INET_EGRESS: + case VKI_BPF_CGROUP_INET_SOCK_CREATE: + case VKI_BPF_CGROUP_SOCK_OPS: + case VKI_BPF_CGROUP_DEVICE: + case VKI_BPF_CGROUP_INET4_BIND: + case VKI_BPF_CGROUP_INET6_BIND: + case VKI_BPF_CGROUP_INET4_CONNECT: + case VKI_BPF_CGROUP_INET6_CONNECT: + case VKI_BPF_CGROUP_INET4_POST_BIND: + case VKI_BPF_CGROUP_INET6_POST_BIND: + case VKI_BPF_CGROUP_UDP4_SENDMSG: + case VKI_BPF_CGROUP_UDP6_SENDMSG: + case VKI_BPF_LIRC_MODE2: + default: + break; + } + } + /* fall through */ + case VKI_BPF_PROG_ATTACH: + /* Attach eBPF program to kernel attach point. */ + if (ML_(safe_to_deref)(attr, ARG3)) { + if (!ML_(fd_allowed)(attr->target_fd, "bpf", tid, False) || + !ML_(fd_allowed)(attr->attach_bpf_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } + } break; case VKI_BPF_PROG_TEST_RUN: /* Test prog. Read data_in, write up to data_size_out to data_out. */ if (ML_(safe_to_deref)(attr, ARG3) && attr->test.data_in != 0 && attr->test.data_out != 0) { + if (!ML_(fd_allowed)(attr->test.prog_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } PRE_MEM_READ("bpf(attr->test.data_in)", attr->test.data_in, attr->test.data_size_in); /* @@ -11747,6 +11862,10 @@ PRE(sys_bpf) case VKI_BPF_OBJ_GET_INFO_BY_FD: /* Get info for eBPF map or program. Write info. */ if (ML_(safe_to_deref)(attr, ARG3) && attr->info.info != 0) { + if (!ML_(fd_allowed)(attr->info.bpf_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } /* Get size of struct to write: is object a program or a map? */ res = bpf_obj_get_info_size(attr->info.bpf_fd); if (res) @@ -11764,13 +11883,23 @@ PRE(sys_bpf) * Query list of eBPF program attached to cgroup. * Write array of ids (up to attr->query.prog_cnt u32-long ids). */ - if (ML_(safe_to_deref)(attr, ARG3) && attr->query.prog_ids != 0) + if (ML_(safe_to_deref)(attr, ARG3) && attr->query.prog_ids != 0) { + if (!ML_(fd_allowed)(attr->query.target_fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } PRE_MEM_WRITE("bpf(attr->query.prog_ids)", attr->query.prog_ids, attr->query.prog_cnt * sizeof(__vki_u32)); + } break; case VKI_BPF_RAW_TRACEPOINT_OPEN: /* Open raw tracepoint. Read tracepoint name. */ if (ML_(safe_to_deref)(attr, ARG3)) { + if (!ML_(fd_allowed)(attr->raw_tracepoint.prog_fd, + "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } /* Name is limited to 128 characters in kernel/bpf/syscall.c. */ pre_asciiz_str(tid, attr->raw_tracepoint.name, 128, "bpf(attr->raw_tracepoint.name)"); @@ -11790,6 +11919,10 @@ PRE(sys_bpf) case VKI_BPF_TASK_FD_QUERY: /* Get info about the task. Write collected info. */ if (ML_(safe_to_deref)(attr, ARG3)) { + if (!ML_(fd_allowed)(attr->task_fd_query.fd, "bpf", tid, False)) { + SET_STATUS_Failure(VKI_EBADF); + break; + } if (attr->task_fd_query.buf_len > 0) { /* Write task or perf event name. */ PRE_MEM_WRITE("bpf(attr->task_fd_query.buf)", @@ -11814,19 +11947,28 @@ POST(sys_bpf) vg_assert(SUCCESS); switch (ARG1) { - case VKI_BPF_MAP_CREATE: case VKI_BPF_MAP_UPDATE_ELEM: case VKI_BPF_MAP_DELETE_ELEM: case VKI_BPF_OBJ_PIN: - case VKI_BPF_OBJ_GET: case VKI_BPF_PROG_ATTACH: case VKI_BPF_PROG_DETACH: case VKI_BPF_PROG_GET_NEXT_ID: case VKI_BPF_MAP_GET_NEXT_ID: + break; + /* Following commands have bpf() return a file descriptor. */ + case VKI_BPF_MAP_CREATE: + case VKI_BPF_OBJ_GET: case VKI_BPF_PROG_GET_FD_BY_ID: case VKI_BPF_MAP_GET_FD_BY_ID: case VKI_BPF_BTF_GET_FD_BY_ID: case VKI_BPF_RAW_TRACEPOINT_OPEN: + if (!ML_(fd_allowed)(RES, "bpf", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure(VKI_EMFILE); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_nameless)(tid, RES); + } break; /* * TODO: Is there a way to pass information between PRE and POST hooks? @@ -11841,8 +11983,16 @@ POST(sys_bpf) POST_MEM_WRITE(attr->next_key, key_size); break; case VKI_BPF_PROG_LOAD: - if (attr->log_level) - POST_MEM_WRITE(attr->log_buf, attr->log_size); + /* Return a file descriptor for loaded program, write into log_buf. */ + if (!ML_(fd_allowed)(RES, "bpf", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure(VKI_EMFILE); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_nameless)(tid, RES); + if (attr->log_level) + POST_MEM_WRITE(attr->log_buf, attr->log_size); + } break; case VKI_BPF_PROG_TEST_RUN: POST_MEM_WRITE(attr->test.data_out, attr->test.data_size_out); @@ -11857,8 +12007,15 @@ POST(sys_bpf) break; case VKI_BPF_BTF_LOAD: /* Return a file descriptor for BTF data, write into btf_log_buf. */ - if (attr->btf_log_level) - POST_MEM_WRITE(attr->btf_log_buf, attr->btf_log_size); + if (!ML_(fd_allowed)(RES, "bpf", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure(VKI_EMFILE); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_nameless)(tid, RES); + if (attr->btf_log_level) + POST_MEM_WRITE(attr->btf_log_buf, attr->btf_log_size); + } break; case VKI_BPF_TASK_FD_QUERY: POST_MEM_WRITE(attr->task_fd_query.buf, attr->task_fd_query.buf_len); diff --git a/include/vki/vki-linux.h b/include/vki/vki-linux.h index 44b683e..9ffb002 100644 --- a/include/vki/vki-linux.h +++ b/include/vki/vki-linux.h @@ -4865,6 +4865,49 @@ enum vki_bpf_cmd { VKI_BPF_TASK_FD_QUERY, }; +enum vki_bpf_map_type { + VKI_BPF_MAP_TYPE_UNSPEC, + VKI_BPF_MAP_TYPE_HASH, + VKI_BPF_MAP_TYPE_ARRAY, + VKI_BPF_MAP_TYPE_PROG_ARRAY, + VKI_BPF_MAP_TYPE_PERF_EVENT_ARRAY, + VKI_BPF_MAP_TYPE_PERCPU_HASH, + VKI_BPF_MAP_TYPE_PERCPU_ARRAY, + VKI_BPF_MAP_TYPE_STACK_TRACE, + VKI_BPF_MAP_TYPE_CGROUP_ARRAY, + VKI_BPF_MAP_TYPE_LRU_HASH, + VKI_BPF_MAP_TYPE_LRU_PERCPU_HASH, + VKI_BPF_MAP_TYPE_LPM_TRIE, + VKI_BPF_MAP_TYPE_ARRAY_OF_MAPS, + VKI_BPF_MAP_TYPE_HASH_OF_MAPS, + VKI_BPF_MAP_TYPE_DEVMAP, + VKI_BPF_MAP_TYPE_SOCKMAP, + VKI_BPF_MAP_TYPE_CPUMAP, + VKI_BPF_MAP_TYPE_XSKMAP, + VKI_BPF_MAP_TYPE_SOCKHASH, +}; + +enum vki_bpf_attach_type { + VKI_BPF_CGROUP_INET_INGRESS, + VKI_BPF_CGROUP_INET_EGRESS, + VKI_BPF_CGROUP_INET_SOCK_CREATE, + VKI_BPF_CGROUP_SOCK_OPS, + VKI_BPF_SK_SKB_STREAM_PARSER, + VKI_BPF_SK_SKB_STREAM_VERDICT, + VKI_BPF_CGROUP_DEVICE, + VKI_BPF_SK_MSG_VERDICT, + VKI_BPF_CGROUP_INET4_BIND, + VKI_BPF_CGROUP_INET6_BIND, + VKI_BPF_CGROUP_INET4_CONNECT, + VKI_BPF_CGROUP_INET6_CONNECT, + VKI_BPF_CGROUP_INET4_POST_BIND, + VKI_BPF_CGROUP_INET6_POST_BIND, + VKI_BPF_CGROUP_UDP4_SENDMSG, + VKI_BPF_CGROUP_UDP6_SENDMSG, + VKI_BPF_LIRC_MODE2, + __VKI_MAX_BPF_ATTACH_TYPE +}; + #define VKI_BPF_OBJ_NAME_LEN 16U #define __vki_aligned_u64 __vki_u64 __attribute__((aligned(8))) |
|
From: Tom H. <tom...@so...> - 2018-08-14 19:48:13
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=1d933b5a4afdbc2eff2fc27027847998b84393c5 commit 1d933b5a4afdbc2eff2fc27027847998b84393c5 Author: Quentin Monnet <que...@ne...> Date: Thu Apr 5 00:40:49 2018 +0100 Add support for bpf system call Fixes: 388786 - Support bpf syscall in amd64 Linux Add support for bpf() Linux-specific system call on amd64 platform. The bpf() syscall is used to handle eBPF objects (programs and maps), and can be used for a number of operations. It takes three arguments: - "cmd" is an integer encoding a subcommand to run. Available subcommand include loading a new program, creating a map or updating its entries, retrieving information about an eBPF object, and may others. - "attr" is a pointer to an object of type union bpf_attr. This object converts to a struct related to selected subcommand, and embeds the various parameters used with this subcommand. Some of those parameters are read by the kernel (example for an eBPF map lookup: the key of the entry to lookup), others are written into (the value retrieved from the map lookup). - "attr_size" is the size of the object pointed by "attr". Since the action performed by the kernel, and the way "attr" attributes are processed depends on the subcommand in use, the PRE() and POST() wrappers need to make the distinction as well. For each subcommand, mark the attributes that are read or written. For some map operations, the only way to infer the size of the memory areas used for read or write operations seems to involve reading from /proc/<pid>/fdinfo/<fd> in order to retrieve the size of keys and values for this map. The definitions of union bpf_attr and of other eBPF-related elements required for adequately performing the checks were added to the Linux header file. Processing related to file descriptors is added in a follow-up patch. Diff: --- NEWS | 1 + coregrind/m_syswrap/priv_syswrap-linux.h | 3 + coregrind/m_syswrap/syswrap-amd64-linux.c | 2 +- coregrind/m_syswrap/syswrap-linux.c | 291 ++++++++++++++++++++++++++++++ include/vki/vki-linux.h | 201 +++++++++++++++++++++ 5 files changed, 497 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index e1bb4ad..dcbfce6 100644 --- a/NEWS +++ b/NEWS @@ -121,6 +121,7 @@ where XXXXXX is the bug number as listed below. 387766 asm shifts cause false positive "Conditional jump or move depends on uninitialised value" 387773 .gnu_debugaltlink paths resolve relative to .debug file, not symlink +388786 Support bpf syscall in amd64 Linux 388862 Add replacements for wmemchr and wcsnlen on Linux 389065 valgrind meets gcc flag -Wlogical-op 389373 exp-sgcheck the 'impossible' happened as Ist_LoadG is not instrumented diff --git a/coregrind/m_syswrap/priv_syswrap-linux.h b/coregrind/m_syswrap/priv_syswrap-linux.h index 296ef65..f76191a 100644 --- a/coregrind/m_syswrap/priv_syswrap-linux.h +++ b/coregrind/m_syswrap/priv_syswrap-linux.h @@ -295,6 +295,9 @@ DECL_TEMPLATE(linux, sys_syncfs); DECL_TEMPLATE(linux, sys_membarrier); +// Linux-specific (new in Linux 3.18) +DECL_TEMPLATE(linux, sys_bpf); + // Linux-specific (new in Linux 4.11) DECL_TEMPLATE(linux, sys_statx); diff --git a/coregrind/m_syswrap/syswrap-amd64-linux.c b/coregrind/m_syswrap/syswrap-amd64-linux.c index 9255e7b..60fb5ff 100644 --- a/coregrind/m_syswrap/syswrap-amd64-linux.c +++ b/coregrind/m_syswrap/syswrap-amd64-linux.c @@ -846,7 +846,7 @@ static SyscallTableEntry syscall_table[] = { LINXY(__NR_memfd_create, sys_memfd_create), // 319 // LIN__(__NR_kexec_file_load, sys_ni_syscall), // 320 -// LIN__(__NR_bpf, sys_ni_syscall), // 321 + LINXY(__NR_bpf, sys_bpf), // 321 LINXY(__NR_statx, sys_statx), // 332 diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c index b0d6541..1e6f5fc 100644 --- a/coregrind/m_syswrap/syswrap-linux.c +++ b/coregrind/m_syswrap/syswrap-linux.c @@ -11580,6 +11580,297 @@ PRE(sys_kcmp) } } +/* --------------------------------------------------------------------- + bpf wrappers + ------------------------------------------------------------------ */ + +static Bool bpf_map_get_sizes(Int fd, UInt *key_size, UInt *value_size) +{ + HChar path[32], buf[1024]; /* large enough */ + SysRes sres; + HChar *comp; + Int proc_fd; + + *key_size = 0; + *value_size = 0; + + VG_(sprintf)(path, "/proc/%d/fdinfo/%d", VG_(getpid)(), fd); + sres = VG_(open)(path, VKI_O_RDONLY, 0); + if (sr_isError(sres)) + return False; + proc_fd = sr_Res(sres); + + if (VG_(read)(proc_fd, buf, sizeof(buf)) <= 0) + return False; + VG_(close)(proc_fd); + + comp = VG_(strstr)(buf, "key_size:"); + if (comp) + *key_size = VG_(strtoull10)(comp + sizeof("key_size:"), NULL); + + comp = VG_(strstr)(buf, "value_size:"); + if (comp) + *value_size = VG_(strtoull10)(comp + sizeof("value_size:"), NULL); + + return (*key_size && *value_size); +} + +/* + * From a file descriptor for an eBPF object, try to determine the size of the + * struct that will be written, i.e. determine if object is a map or a program. + * There is no direct way to do this, so parse /proc/<pid>/fdinfo/<fd> and + * search for strings "prog_type" or "map_type". + */ +static UInt bpf_obj_get_info_size(Int fd) +{ + HChar path[32], buf[1024]; /* large enough */ + SysRes sres; + Int proc_fd; + + VG_(sprintf)(path, "/proc/%d/fdinfo/%d", VG_(getpid)(), fd); + sres = VG_(open)(path, VKI_O_RDONLY, 0); + if (sr_isError(sres)) + return 0; + proc_fd = sr_Res(sres); + + if (VG_(read)(proc_fd, buf, sizeof(buf)) <= 0) + return 0; + VG_(close)(proc_fd); + + if (VG_(strstr)(buf, "prog_type:")) + return sizeof(struct vki_bpf_prog_info); + + if (VG_(strstr)(buf, "map_type:")) + return sizeof(struct vki_bpf_map_info); + + return 0; +} + +PRE(sys_bpf) +{ + union vki_bpf_attr *attr = (union vki_bpf_attr *)(Addr)ARG2; + UInt res, key_size, value_size; + + PRE_REG_READ3(long, "bpf", + int, cmd, union vki_bpf_attr *, attr, unsigned int, size); + PRINT("bpf ( %ld, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", + ARG1, ARG2, ARG3); + switch (ARG1) { + case VKI_BPF_MAP_CREATE: + case VKI_BPF_PROG_ATTACH: + case VKI_BPF_PROG_DETACH: + case VKI_BPF_PROG_GET_NEXT_ID: + case VKI_BPF_MAP_GET_NEXT_ID: + case VKI_BPF_PROG_GET_FD_BY_ID: + case VKI_BPF_MAP_GET_FD_BY_ID: + case VKI_BPF_BTF_GET_FD_BY_ID: + break; + case VKI_BPF_MAP_LOOKUP_ELEM: + /* Perform a lookup on an eBPF map. Read key, write value. */ + if (ML_(safe_to_deref)(attr, ARG3) && + attr->key != 0 && attr->value != 0) { + /* Get size of key and value for this map. */ + if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) { + PRE_MEM_READ("bpf(attr->key)", attr->key, key_size); + PRE_MEM_WRITE("bpf(attr->value)", attr->value, value_size); + } + } + break; + case VKI_BPF_MAP_UPDATE_ELEM: + /* Add or update a map element in kernel. Read key, read value. */ + if (ML_(safe_to_deref)(attr, ARG3) && + attr->key != 0 && attr->value != 0) { + /* Get size of key and value for this map. */ + if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) { + PRE_MEM_READ("bpf(attr->key)", attr->key, key_size); + PRE_MEM_READ("bpf(attr->value)", attr->value, value_size); + } + } + break; + case VKI_BPF_MAP_DELETE_ELEM: + /* Delete a map element in kernel. Read key from user space. */ + if (ML_(safe_to_deref)(attr, ARG3) && attr->key != 0) { + /* Get size of key for this map. */ + if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) + PRE_MEM_READ("bpf(attr->key)", attr->key, key_size); + } + break; + case VKI_BPF_MAP_GET_NEXT_KEY: + /* From a key, get next key for the map. Read key, write next key. */ + if (ML_(safe_to_deref)(attr, ARG3) && + attr->key != 0 && attr->next_key != 0) { + /* Get size of key for this map. */ + if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) { + PRE_MEM_READ("bpf(attr->key)", attr->key, key_size); + PRE_MEM_WRITE("bpf(attr->next_key)", attr->next_key, key_size); + } + } + break; + case VKI_BPF_PROG_LOAD: + /* Load a program into the kernel from an array of instructions. */ + if (ML_(safe_to_deref)(attr, ARG3)) { + /* Read instructions, license, program name. */ + PRE_MEM_READ("bpf(attr->insns)", attr->insns, + attr->insn_cnt * sizeof(struct vki_bpf_insn)); + /* License is limited to 128 characters in kernel/bpf/syscall.c. */ + pre_asciiz_str(tid, attr->license, 128, "bpf(attr->license)"); + pre_asciiz_str(tid, (unsigned long int)attr->prog_name, + VKI_BPF_OBJ_NAME_LEN, "bpf(attr->prog_name)"); + /* Possibly write up to log_len into user space log buffer. */ + if (attr->log_level && attr->log_size > 128 && attr->log_buf != 0) + PRE_MEM_WRITE("bpf(attr->log_buf)", + attr->log_buf, attr->log_size); + } + break; + case VKI_BPF_OBJ_PIN: + /* Pin eBPF program or map to given location under /sys/fs/bpf/. */ + /* fall through */ + case VKI_BPF_OBJ_GET: + /* Get pinned eBPF program or map. Read path name. */ + if (ML_(safe_to_deref)(attr, ARG3)) + pre_asciiz_str(tid, attr->pathname, VKI_BPF_OBJ_NAME_LEN, + "bpf(attr->pathname)"); + break; + case VKI_BPF_PROG_TEST_RUN: + /* Test prog. Read data_in, write up to data_size_out to data_out. */ + if (ML_(safe_to_deref)(attr, ARG3) && + attr->test.data_in != 0 && attr->test.data_out != 0) { + PRE_MEM_READ("bpf(attr->test.data_in)", + attr->test.data_in, attr->test.data_size_in); + /* + * TODO: Kernel writes to data_out but we do not know the size yet. + * PRE_MEM_WRITE("bpf(attr->test.data_out)", + * attr->test.data_out, ??); + */ + } + break; + case VKI_BPF_OBJ_GET_INFO_BY_FD: + /* Get info for eBPF map or program. Write info. */ + if (ML_(safe_to_deref)(attr, ARG3) && attr->info.info != 0) { + /* Get size of struct to write: is object a program or a map? */ + res = bpf_obj_get_info_size(attr->info.bpf_fd); + if (res) + PRE_MEM_WRITE("bpf(attr->info.info)", attr->info.info, + VG_MIN(attr->info.info_len, res)); + else + PRE_MEM_WRITE("bpf(attr->info.info)", attr->info.info, + VG_MIN(attr->info.info_len, + VG_MAX(sizeof(struct vki_bpf_prog_info), + sizeof(struct vki_bpf_map_info)))); + } + break; + case VKI_BPF_PROG_QUERY: + /* + * Query list of eBPF program attached to cgroup. + * Write array of ids (up to attr->query.prog_cnt u32-long ids). + */ + if (ML_(safe_to_deref)(attr, ARG3) && attr->query.prog_ids != 0) + PRE_MEM_WRITE("bpf(attr->query.prog_ids)", attr->query.prog_ids, + attr->query.prog_cnt * sizeof(__vki_u32)); + break; + case VKI_BPF_RAW_TRACEPOINT_OPEN: + /* Open raw tracepoint. Read tracepoint name. */ + if (ML_(safe_to_deref)(attr, ARG3)) { + /* Name is limited to 128 characters in kernel/bpf/syscall.c. */ + pre_asciiz_str(tid, attr->raw_tracepoint.name, 128, + "bpf(attr->raw_tracepoint.name)"); + } + break; + case VKI_BPF_BTF_LOAD: + /* Load BTF information about a program into the kernel. */ + if (ML_(safe_to_deref)(attr, ARG3)) { + /* Read BTF data. */ + PRE_MEM_READ("bpf(attr->btf)", attr->btf, attr->btf_size); + /* Possibly write up to btf_log_len into user space log buffer. */ + if (attr->btf_log_level && attr->btf_log_size > 128 && + attr->btf_log_buf != 0) + PRE_MEM_WRITE("bpf(attr->btf_log_buf)", + attr->btf_log_buf, attr->btf_log_size); + } + case VKI_BPF_TASK_FD_QUERY: + /* Get info about the task. Write collected info. */ + if (ML_(safe_to_deref)(attr, ARG3)) { + if (attr->task_fd_query.buf_len > 0) { + /* Write task or perf event name. */ + PRE_MEM_WRITE("bpf(attr->task_fd_query.buf)", + attr->task_fd_query.buf, + attr->task_fd_query.buf_len); + } + } + break; + default: + VG_(message)(Vg_DebugMsg, + "FATAL: unhandled eBPF command %lu\n", ARG1); + VG_(core_panic)("... bye!\n"); + break; + } +} + +POST(sys_bpf) +{ + union vki_bpf_attr *attr = (union vki_bpf_attr *)(Addr)ARG2; + UInt key_size, value_size; + + vg_assert(SUCCESS); + + switch (ARG1) { + case VKI_BPF_MAP_CREATE: + case VKI_BPF_MAP_UPDATE_ELEM: + case VKI_BPF_MAP_DELETE_ELEM: + case VKI_BPF_OBJ_PIN: + case VKI_BPF_OBJ_GET: + case VKI_BPF_PROG_ATTACH: + case VKI_BPF_PROG_DETACH: + case VKI_BPF_PROG_GET_NEXT_ID: + case VKI_BPF_MAP_GET_NEXT_ID: + case VKI_BPF_PROG_GET_FD_BY_ID: + case VKI_BPF_MAP_GET_FD_BY_ID: + case VKI_BPF_BTF_GET_FD_BY_ID: + case VKI_BPF_RAW_TRACEPOINT_OPEN: + break; + /* + * TODO: Is there a way to pass information between PRE and POST hooks? + * To avoid querying again for the size of keys and values. + */ + case VKI_BPF_MAP_LOOKUP_ELEM: + if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) + POST_MEM_WRITE(attr->value, value_size); + break; + case VKI_BPF_MAP_GET_NEXT_KEY: + if (bpf_map_get_sizes(attr->map_fd, &key_size, &value_size)) + POST_MEM_WRITE(attr->next_key, key_size); + break; + case VKI_BPF_PROG_LOAD: + if (attr->log_level) + POST_MEM_WRITE(attr->log_buf, attr->log_size); + break; + case VKI_BPF_PROG_TEST_RUN: + POST_MEM_WRITE(attr->test.data_out, attr->test.data_size_out); + break; + case VKI_BPF_OBJ_GET_INFO_BY_FD: + POST_MEM_WRITE(attr->info.info, attr->info.info_len); + break; + case VKI_BPF_PROG_QUERY: + if (attr->query.prog_ids) + POST_MEM_WRITE(attr->query.prog_ids, + attr->query.prog_cnt * sizeof(__vki_u32)); + break; + case VKI_BPF_BTF_LOAD: + /* Return a file descriptor for BTF data, write into btf_log_buf. */ + if (attr->btf_log_level) + POST_MEM_WRITE(attr->btf_log_buf, attr->btf_log_size); + break; + case VKI_BPF_TASK_FD_QUERY: + POST_MEM_WRITE(attr->task_fd_query.buf, attr->task_fd_query.buf_len); + break; + default: + VG_(message)(Vg_DebugMsg, + "FATAL: unhandled eBPF command %lu\n", ARG1); + VG_(core_panic)("... bye!\n"); + break; + } +} + #undef PRE #undef POST diff --git a/include/vki/vki-linux.h b/include/vki/vki-linux.h index 1beeebb..44b683e 100644 --- a/include/vki/vki-linux.h +++ b/include/vki/vki-linux.h @@ -4829,6 +4829,207 @@ struct vki_blk_zone_range { #define VKI_BLKREPORTZONE _VKI_IOWR(0x12, 130, struct vki_blk_zone_report) #define VKI_BLKRESETZONE _VKI_IOW(0x12, 131, struct vki_blk_zone_range) +//---------------------------------------------------------------------- +// From linux-4.18/include/uapi/linux/bpf.h +//---------------------------------------------------------------------- + +struct vki_bpf_insn { + __vki_u8 code; /* opcode */ + __vki_u8 dst_reg:4; /* dest register */ + __vki_u8 src_reg:4; /* source register */ + __vki_s16 off; /* signed offset */ + __vki_s32 imm; /* signed immediate constant */ +}; + +enum vki_bpf_cmd { + VKI_BPF_MAP_CREATE, + VKI_BPF_MAP_LOOKUP_ELEM, + VKI_BPF_MAP_UPDATE_ELEM, + VKI_BPF_MAP_DELETE_ELEM, + VKI_BPF_MAP_GET_NEXT_KEY, + VKI_BPF_PROG_LOAD, + VKI_BPF_OBJ_PIN, + VKI_BPF_OBJ_GET, + VKI_BPF_PROG_ATTACH, + VKI_BPF_PROG_DETACH, + VKI_BPF_PROG_TEST_RUN, + VKI_BPF_PROG_GET_NEXT_ID, + VKI_BPF_MAP_GET_NEXT_ID, + VKI_BPF_PROG_GET_FD_BY_ID, + VKI_BPF_MAP_GET_FD_BY_ID, + VKI_BPF_OBJ_GET_INFO_BY_FD, + VKI_BPF_PROG_QUERY, + VKI_BPF_RAW_TRACEPOINT_OPEN, + VKI_BPF_BTF_LOAD, + VKI_BPF_BTF_GET_FD_BY_ID, + VKI_BPF_TASK_FD_QUERY, +}; + +#define VKI_BPF_OBJ_NAME_LEN 16U + +#define __vki_aligned_u64 __vki_u64 __attribute__((aligned(8))) +union vki_bpf_attr { + struct { /* anonymous struct used by BPF_MAP_CREATE command */ + __vki_u32 map_type; /* one of enum bpf_map_type */ + __vki_u32 key_size; /* size of key in bytes */ + __vki_u32 value_size; /* size of value in bytes */ + __vki_u32 max_entries; /* max number of entries in a map */ + __vki_u32 map_flags; /* BPF_MAP_CREATE related + * flags defined above. + */ + __vki_u32 inner_map_fd; /* fd pointing to the inner map */ + __vki_u32 numa_node; /* numa node (effective only if + * BPF_F_NUMA_NODE is set). + */ + char map_name[VKI_BPF_OBJ_NAME_LEN]; + __vki_u32 map_ifindex; /* ifindex of netdev to create on */ + __vki_u32 btf_fd; /* fd pointing to a BTF type data */ + __vki_u32 btf_key_type_id; /* BTF type_id of the key */ + __vki_u32 btf_value_type_id; /* BTF type_id of the value */ + }; + + struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ + __vki_u32 map_fd; + __vki_aligned_u64 key; + union { + __vki_aligned_u64 value; + __vki_aligned_u64 next_key; + }; + __vki_u64 flags; + }; + + struct { /* anonymous struct used by BPF_PROG_LOAD command */ + __vki_u32 prog_type; /* one of enum bpf_prog_type */ + __vki_u32 insn_cnt; + __vki_aligned_u64 insns; + __vki_aligned_u64 license; + __vki_u32 log_level; /* verbosity level of verifier */ + __vki_u32 log_size; /* size of user buffer */ + __vki_aligned_u64 log_buf; /* user supplied buffer */ + __vki_u32 kern_version; /* checked when prog_type=kprobe */ + __vki_u32 prog_flags; + char prog_name[VKI_BPF_OBJ_NAME_LEN]; + __vki_u32 prog_ifindex; /* ifindex of netdev to prep for */ + /* For some prog types expected attach type must be known at + * load time to verify attach type specific parts of prog + * (context accesses, allowed helpers, etc). + */ + __vki_u32 expected_attach_type; + }; + + struct { /* anonymous struct used by BPF_OBJ_* commands */ + __vki_aligned_u64 pathname; + __vki_u32 bpf_fd; + __vki_u32 file_flags; + }; + + struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */ + __vki_u32 target_fd; /* container object to attach to */ + __vki_u32 attach_bpf_fd; /* eBPF program to attach */ + __vki_u32 attach_type; + __vki_u32 attach_flags; + }; + + struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */ + __vki_u32 prog_fd; + __vki_u32 retval; + __vki_u32 data_size_in; + __vki_u32 data_size_out; + __vki_aligned_u64 data_in; + __vki_aligned_u64 data_out; + __vki_u32 repeat; + __vki_u32 duration; + } test; + + struct { /* anonymous struct used by BPF_*_GET_*_ID */ + union { + __vki_u32 start_id; + __vki_u32 prog_id; + __vki_u32 map_id; + __vki_u32 btf_id; + }; + __vki_u32 next_id; + __vki_u32 open_flags; + }; + + struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */ + __vki_u32 bpf_fd; + __vki_u32 info_len; + __vki_aligned_u64 info; + } info; + + struct { /* anonymous struct used by BPF_PROG_QUERY command */ + __vki_u32 target_fd; /* container object to query */ + __vki_u32 attach_type; + __vki_u32 query_flags; + __vki_u32 attach_flags; + __vki_aligned_u64 prog_ids; + __vki_u32 prog_cnt; + } query; + + struct { + __vki_u64 name; + __vki_u32 prog_fd; + } raw_tracepoint; + + struct { /* anonymous struct for BPF_BTF_LOAD */ + __vki_aligned_u64 btf; + __vki_aligned_u64 btf_log_buf; + __vki_u32 btf_size; + __vki_u32 btf_log_size; + __vki_u32 btf_log_level; + }; + + struct { + __vki_u32 pid; /* input: pid */ + __vki_u32 fd; /* input: fd */ + __vki_u32 flags; /* input: flags */ + __vki_u32 buf_len; /* input/output: buf len */ + __vki_aligned_u64 buf; /* input/output: + * tp_name for tracepoint + * symbol for kprobe + * filename for uprobe + */ + __vki_u32 prog_id; /* output: prod_id */ + __vki_u32 fd_type; /* output: BPF_FD_TYPE_* */ + __vki_u64 probe_offset; /* output: probe_offset */ + __vki_u64 probe_addr; /* output: probe_addr */ + } task_fd_query; +} __attribute__((aligned(8))); + +#define VKI_BPF_TAG_SIZE 8 + +struct vki_bpf_prog_info { + __vki_u32 type; + __vki_u32 id; + __vki_u8 tag[VKI_BPF_TAG_SIZE]; + __vki_u32 jited_prog_len; + __vki_u32 xlated_prog_len; + __vki_aligned_u64 jited_prog_insns; + __vki_aligned_u64 xlated_prog_insns; + __vki_u64 load_time; /* ns since boottime */ + __vki_u32 created_by_uid; + __vki_u32 nr_map_ids; + __vki_aligned_u64 map_ids; + char name[VKI_BPF_OBJ_NAME_LEN]; + __vki_u32 ifindex; + __vki_u64 netns_dev; + __vki_u64 netns_ino; +} __attribute__((aligned(8))); + +struct vki_bpf_map_info { + __vki_u32 type; + __vki_u32 id; + __vki_u32 key_size; + __vki_u32 value_size; + __vki_u32 max_entries; + __vki_u32 map_flags; + char name[VKI_BPF_OBJ_NAME_LEN]; + __vki_u32 ifindex; + __vki_u64 netns_dev; + __vki_u64 netns_ino; +} __attribute__((aligned(8))); + /*--------------------------------------------------------------------*/ /*--- end ---*/ /*--------------------------------------------------------------------*/ |
|
From: Tom H. <tom...@so...> - 2018-08-14 19:48:06
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=c9d555dafad9215f8e9db941af012296e35106df commit c9d555dafad9215f8e9db941af012296e35106df Author: Quentin Monnet <que...@ne...> Date: Sat Apr 14 23:23:11 2018 +0100 Move pre_check for ASCII string out of PRE(sys_prctl) The sys_prctl wrapper with PR_SET_NAME option reads an ASCII string passed as its second argument. This string is supposed to be shorter than a given limit. As the actual length of the string is unknown, the PRE() wrapper performs a number of checks on it, including, in worst case, trying to dereference it byte by byte. To avoid re-implementing all this logic for other wrappers that could need it, get the string processing out of the wrapper and move it to a static function. Note that passing tid as an argument to the function is required for macros PRE_MEM_RASCIIZ and PRE_MEM_READ to work properly. Diff: --- coregrind/m_syswrap/syswrap-linux.c | 52 ++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c index bd7d447..b0d6541 100644 --- a/coregrind/m_syswrap/syswrap-linux.c +++ b/coregrind/m_syswrap/syswrap-linux.c @@ -1389,6 +1389,36 @@ POST(sys_sysctl) } } +static void pre_asciiz_str(ThreadId tid, Addr str, SizeT maxlen, + const char *attr_name) +{ + const HChar *step_str = (const HChar *)str; + SizeT len; + UInt i; + + /* + * The name can be up to maxlen bytes long, including the terminating null + * byte. So do not check more than maxlen bytes. + */ + if (ML_(safe_to_deref)((const HChar *)str, maxlen)) { + len = VG_(strnlen)((const HChar *)str, maxlen); + if (len < maxlen) + PRE_MEM_RASCIIZ(attr_name, str); + else + PRE_MEM_READ(attr_name, str, maxlen); + } else { + /* + * Do it the slow way, one byte at a time, while checking for terminating + * '\0'. + */ + for (i = 0; i < maxlen; i++) { + PRE_MEM_READ(attr_name, (Addr)&step_str[i], 1); + if (!ML_(safe_to_deref)(&step_str[i], 1) || step_str[i] == '\0') + break; + } + } +} + PRE(sys_prctl) { *flags |= SfMayBlock; @@ -1442,27 +1472,7 @@ PRE(sys_prctl) break; case VKI_PR_SET_NAME: PRE_REG_READ2(int, "prctl", int, option, char *, name); - /* The name can be up to TASK_COMM_LEN(16) bytes long, including - the terminating null byte. So do not check more than 16 bytes. */ - if (ML_(safe_to_deref)((const HChar *) (Addr)ARG2, VKI_TASK_COMM_LEN)) { - SizeT len = VG_(strnlen)((const HChar *) (Addr)ARG2, - VKI_TASK_COMM_LEN); - if (len < VKI_TASK_COMM_LEN) { - PRE_MEM_RASCIIZ("prctl(set-name)", ARG2); - } else { - PRE_MEM_READ("prctl(set-name)", ARG2, VKI_TASK_COMM_LEN); - } - } else { - /* Do it the slow way, one byte at a time, while checking for - terminating '\0'. */ - const HChar *name = (const HChar *) (Addr)ARG2; - for (UInt i = 0; i < VKI_TASK_COMM_LEN; i++) { - PRE_MEM_READ("prctl(set-name)", (Addr) &name[i], 1); - if (!ML_(safe_to_deref)(&name[i], 1) || name[i] == '\0') { - break; - } - } - } + pre_asciiz_str(tid, ARG2, VKI_TASK_COMM_LEN, "prctl(set-name)"); break; case VKI_PR_GET_NAME: PRE_REG_READ2(int, "prctl", int, option, char *, name); |
|
From: Julian S. <se...@so...> - 2018-08-14 08:18:30
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=e752326cc050803c3bcfde1f8606bead66ff9642 commit e752326cc050803c3bcfde1f8606bead66ff9642 Author: Julian Seward <js...@ac...> Date: Tue Aug 14 10:13:46 2018 +0200 VG_(di_notify_mmap): once we've read debuginfo for an object, ignore all further mappings. n-i-bz. Once we've read debuginfo for an object, ignore all further mappings. If we don't do that, applications that mmap in their own objects to inspect them for whatever reason, will cause "irrelevant" mappings to be recorded in the object's fsm.maps table. This can lead to serious problems later on. This has become necessary because 64aa729bfae71561505a40c12755bd6b55bb3061 of Thu Jul 12 2018 (the fix for bug 395682) started recording readonly segments in the fsm.maps table, where before they were ignored. Diff: --- coregrind/m_debuginfo/debuginfo.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c index c36d498..55c05cb 100644 --- a/coregrind/m_debuginfo/debuginfo.c +++ b/coregrind/m_debuginfo/debuginfo.c @@ -1200,6 +1200,32 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) di = find_or_create_DebugInfo_for( filename ); vg_assert(di); + /* Ignore all mappings for this filename once we've read debuginfo for it. + This avoids the confusion of picking up "irrelevant" mappings in + applications which mmap their objects outside of ld.so, for example + Firefox's Gecko profiler. + + What happens in that case is: the application maps the object "ro" for + whatever reason. We record the mapping di->fsm.maps. The application + later unmaps the object. However, the mapping is not removed from + di->fsm.maps. Later, when some other (unrelated) object is mapped (via + ld.so) into that address space, we first unload any debuginfo that has a + mapping intersecting that area. That means we will end up incorrectly + unloading debuginfo for the object with the "irrelevant" mappings. This + causes various problems, not least because it can unload the debuginfo + for libc.so and so cause malloc intercepts to become un-intercepted. + + This fix assumes that all mappings made once we've read debuginfo for + an object are irrelevant. I think that's OK, but need to check with + mjw/thh. */ + if (di->have_dinfo) { + if (debug) + VG_(printf)("di_notify_mmap-4x: " + "ignoring mapping because we already read debuginfo " + "for DebugInfo* %p\n", di); + return 0; + } + if (debug) VG_(printf)("di_notify_mmap-4: " "noting details in DebugInfo* at %p\n", di); @@ -1220,7 +1246,8 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) di->fsm.have_ro_map |= is_ro_map; /* So, finally, are we in an accept state? */ - if (di->fsm.have_rx_map && di->fsm.have_rw_map && !di->have_dinfo) { + vg_assert(!di->have_dinfo); + if (di->fsm.have_rx_map && di->fsm.have_rw_map) { /* Ok, so, finally, we found what we need, and we haven't already read debuginfo for this object. So let's do so now. Yee-ha! */ |