• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vbpf / ebpf-verifier / 14231336081

02 Apr 2025 11:08PM UTC coverage: 87.272% (-0.9%) from 88.177%
14231336081

push

github

web-flow
Propogate ebpf_verifier_options_t to thread_local_options (#856)

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

5 of 5 new or added lines in 2 files covered. (100.0%)

58 existing lines in 19 files now uncovered.

8324 of 9538 relevant lines covered (87.27%)

4881701.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.97
/src/linux/linux_platform.cpp
1
// Copyright (c) Prevail Verifier contributors.
2
// SPDX-License-Identifier: MIT
3
#include <stdexcept>
4
#if __linux__
5
#include <linux/bpf.h>
6
#define PTYPE(name, descr, native_type, prefixes) \
7
    { name, descr, native_type, prefixes }
8
#define PTYPE_PRIVILEGED(name, descr, native_type, prefixes) \
9
    { name, descr, native_type, prefixes, true }
10
#else
11
#define PTYPE(name, descr, native_type, prefixes) \
12
    { name, descr, 0, prefixes }
13
#define PTYPE_PRIVILEGED(name, descr, native_type, prefixes) \
14
    { name, descr, 0, prefixes, true }
15
#endif
16
#include "crab_verifier.hpp"
17
#include "linux/gpl/spec_type_descriptors.hpp"
18
#include "linux_platform.hpp"
19
#include "platform.hpp"
20

21
#include <asm_files.hpp>
22

23
// Map definitions as they appear in an ELF file, so field width matters.
24
struct bpf_load_map_def {
25
    uint32_t type;
26
    uint32_t key_size;
27
    uint32_t value_size;
28
    uint32_t max_entries;
29
    uint32_t map_flags;
30
    uint32_t inner_map_idx;
31
    uint32_t numa_node;
32
};
33

34
static int create_map_linux(uint32_t map_type, uint32_t key_size, uint32_t value_size, uint32_t max_entries,
35
                            ebpf_verifier_options_t options);
36

37
// Allow for comma as a separator between multiple prefixes, to make
38
// the preprocessor treat a prefix list as one macro argument.
39
#define COMMA ,
40

41
const EbpfProgramType linux_socket_filter_program_type =
42
    PTYPE("socket_filter", &g_socket_filter_descr, BPF_PROG_TYPE_SOCKET_FILTER, {"socket"});
43

44
const EbpfProgramType linux_xdp_program_type = PTYPE("xdp", &g_xdp_descr, BPF_PROG_TYPE_XDP, {"xdp"});
45

46
const EbpfProgramType cilium_lxc_program_type = PTYPE("lxc", &g_sched_descr, BPF_PROG_TYPE_SOCKET_FILTER, {});
47

48
const std::vector<EbpfProgramType> linux_program_types = {
49
    PTYPE("unspec", &g_unspec_descr, BPF_PROG_TYPE_UNSPEC, {}),
50
    linux_socket_filter_program_type,
51
    linux_xdp_program_type,
52
    PTYPE("cgroup_device", &g_cgroup_dev_descr, BPF_PROG_TYPE_CGROUP_DEVICE, {"cgroup/dev"}),
53
    PTYPE("cgroup_skb", &g_socket_filter_descr, BPF_PROG_TYPE_CGROUP_SKB, {"cgroup/skb"}),
54
    PTYPE("cgroup_sock", &g_cgroup_sock_descr, BPF_PROG_TYPE_CGROUP_SOCK, {"cgroup/sock"}),
55
    PTYPE_PRIVILEGED("kprobe", &g_kprobe_descr, BPF_PROG_TYPE_KPROBE, {"kprobe/" COMMA "kretprobe/"}),
56
    PTYPE("lwt_in", &g_lwt_inout_descr, BPF_PROG_TYPE_LWT_IN, {"lwt_in"}),
57
    PTYPE("lwt_out", &g_lwt_inout_descr, BPF_PROG_TYPE_LWT_OUT, {"lwt_out"}),
58
    PTYPE("lwt_xmit", &g_lwt_xmit_descr, BPF_PROG_TYPE_LWT_XMIT, {"lwt_xmit"}),
59
    PTYPE("perf_event", &g_perf_event_descr, BPF_PROG_TYPE_PERF_EVENT, {"perf_section" COMMA "perf_event"}),
60
    PTYPE("sched_act", &g_sched_descr, BPF_PROG_TYPE_SCHED_ACT, {"action"}),
61
    PTYPE("sched_cls", &g_sched_descr, BPF_PROG_TYPE_SCHED_CLS, {"classifier"}),
62
    PTYPE("sk_skb", &g_sk_skb_descr, BPF_PROG_TYPE_SK_SKB, {"sk_skb"}),
63
    PTYPE("sock_ops", &g_sock_ops_descr, BPF_PROG_TYPE_SOCK_OPS, {"sockops"}),
64
    PTYPE("tracepoint", &g_tracepoint_descr, BPF_PROG_TYPE_TRACEPOINT, {"tracepoint/"}),
65

66
    // The following types are currently mapped to the socket filter program
67
    // type but should be mapped to the relevant native linux program type
68
    // value.
69
    PTYPE("sk_msg", &g_sk_msg_md, BPF_PROG_TYPE_SOCKET_FILTER, {"sk_msg"}),
70
    PTYPE("raw_tracepoint", &g_tracepoint_descr, BPF_PROG_TYPE_SOCKET_FILTER, {"raw_tracepoint/"}),
71
    PTYPE("cgroup_sock_addr", &g_cgroup_sock_descr, BPF_PROG_TYPE_SOCKET_FILTER, {}),
72
    PTYPE("lwt_seg6local", &g_lwt_xmit_descr, BPF_PROG_TYPE_SOCKET_FILTER, {"lwt_seg6local"}),
73
    PTYPE("lirc_mode2", &g_sk_msg_md, BPF_PROG_TYPE_SOCKET_FILTER, {"lirc_mode2"}),
74
};
75

76
static EbpfProgramType get_program_type_linux(const std::string& section, const std::string& path) {
4,772✔
77
    EbpfProgramType type{};
4,772✔
78

79
    // linux only deduces from section, but cilium and cilium_test have this information
80
    // in the filename:
81
    // * cilium/bpf_xdp.o:from-netdev is XDP
82
    // * bpf_cilium_test/bpf_lb-DLB_L3.o:from-netdev is SK_SKB
83
    if (path.find("cilium") != std::string::npos) {
4,772✔
84
        if (path.find("xdp") != std::string::npos) {
980✔
85
            return linux_xdp_program_type;
257✔
86
        }
87
        if (path.find("lxc") != std::string::npos) {
723✔
88
            return cilium_lxc_program_type;
456✔
89
        }
90
    }
91

92
    for (const EbpfProgramType& t : linux_program_types) {
71,691✔
93
        for (const std::string& prefix : t.section_prefixes) {
138,030✔
94
            if (section.find(prefix) == 0) {
70,398✔
95
                return t;
4,772✔
96
            }
97
        }
98
    }
99

100
    return linux_socket_filter_program_type;
1,986✔
101
}
4,772✔
102

103
#ifdef __linux__
104
#define BPF_MAP_TYPE(x) BPF_MAP_TYPE_##x, #x
105
#else
106
#define BPF_MAP_TYPE(x) 0, #x
107
#endif
108

109
static const EbpfMapType linux_map_types[] = {
110
    {BPF_MAP_TYPE(UNSPEC)},
111
    {BPF_MAP_TYPE(HASH)},
112
    {BPF_MAP_TYPE(ARRAY), true},
113
    {BPF_MAP_TYPE(PROG_ARRAY), true, EbpfMapValueType::PROGRAM},
114
    {BPF_MAP_TYPE(PERF_EVENT_ARRAY), true},
115
    {BPF_MAP_TYPE(PERCPU_HASH)},
116
    {BPF_MAP_TYPE(PERCPU_ARRAY), true},
117
    {BPF_MAP_TYPE(STACK_TRACE)},
118
    {BPF_MAP_TYPE(CGROUP_ARRAY), true},
119
    {BPF_MAP_TYPE(LRU_HASH)},
120
    {BPF_MAP_TYPE(LRU_PERCPU_HASH)},
121
    {BPF_MAP_TYPE(LPM_TRIE)},
122
    {BPF_MAP_TYPE(ARRAY_OF_MAPS), true, EbpfMapValueType::MAP},
123
    {BPF_MAP_TYPE(HASH_OF_MAPS), false, EbpfMapValueType::MAP},
124
    {BPF_MAP_TYPE(DEVMAP)},
125
    {BPF_MAP_TYPE(SOCKMAP)},
126
    {BPF_MAP_TYPE(CPUMAP)},
127
#ifdef BPF_MAP_TYPE_XSKMAP
128
    {BPF_MAP_TYPE(XSKMAP)},
129
    {BPF_MAP_TYPE(SOCKHASH)},
130
    {BPF_MAP_TYPE(CGROUP_STORAGE)},
131
    {BPF_MAP_TYPE(REUSEPORT_SOCKARRAY)},
132
    {BPF_MAP_TYPE(PERCPU_CGROUP_STORAGE)},
133
    {BPF_MAP_TYPE(QUEUE)},
134
    {BPF_MAP_TYPE(STACK)},
135
#endif
136
};
137

138
EbpfMapType get_map_type_linux(uint32_t platform_specific_type) {
14,177✔
139
    const uint32_t index = platform_specific_type;
14,177✔
140
    if ((index == 0) || (index >= sizeof(linux_map_types) / sizeof(linux_map_types[0]))) {
14,177✔
141
        return linux_map_types[0];
24✔
142
    }
143
    EbpfMapType type = linux_map_types[index];
14,153✔
144
#ifdef __linux__
145
    assert(type.platform_specific_type == platform_specific_type);
14,153✔
146
#else
147
    type.platform_specific_type = platform_specific_type;
148
#endif
149
    return type;
14,153✔
150
}
14,153✔
151

152
void parse_maps_section_linux(std::vector<EbpfMapDescriptor>& map_descriptors, const char* data,
283✔
153
                              const size_t map_def_size, const int map_count, const ebpf_platform_t* platform,
154
                              const ebpf_verifier_options_t options) {
155
    // Copy map definitions from the ELF section into a local list.
156
    auto mapdefs = std::vector<bpf_load_map_def>();
283✔
157
    for (int i = 0; i < map_count; i++) {
3,183✔
158
        bpf_load_map_def def = {0};
2,900✔
159
        memcpy(&def, data + i * map_def_size, std::min(map_def_size, sizeof(def)));
3,659✔
160
        mapdefs.emplace_back(def);
2,900✔
161
    }
162

163
    // Add map definitions into the map_descriptors list.
164
    for (const auto& s : mapdefs) {
3,183✔
165
        EbpfMapType type = get_map_type_linux(s.type);
2,900✔
166
        map_descriptors.emplace_back(EbpfMapDescriptor{
2,900✔
167
            .original_fd = create_map_linux(s.type, s.key_size, s.value_size, s.max_entries, options),
2,900✔
168
            .type = s.type,
2,900✔
169
            .key_size = s.key_size,
2,900✔
170
            .value_size = s.value_size,
2,900✔
171
            .max_entries = s.max_entries,
2,900✔
172
            .inner_map_fd = s.inner_map_idx // Temporarily fill in the index. This will be replaced in the
2,900✔
173
                                            // resolve_inner_map_references pass.
174
        });
175
    }
2,900✔
176
}
283✔
177

178
// Initialize the inner_map_fd in each map descriptor.
179
void resolve_inner_map_references_linux(std::vector<EbpfMapDescriptor>& map_descriptors) {
282✔
180
    for (size_t i = 0; i < map_descriptors.size(); i++) {
3,182✔
181
        const unsigned int inner = map_descriptors[i].inner_map_fd; // Get the inner_map_idx back.
2,900✔
182
        if (inner >= map_descriptors.size()) {
2,900✔
183
            throw UnmarshalError("bad inner map index " + std::to_string(inner) + " for map " + std::to_string(i));
×
184
        }
185
        map_descriptors[i].inner_map_fd = map_descriptors.at(inner).original_fd;
2,900✔
186
    }
187
}
282✔
188

189
#if __linux__
190
static int do_bpf(const bpf_cmd cmd, union bpf_attr& attr) { return syscall(321, cmd, &attr, sizeof(attr)); }
×
191
#endif
192

193
/** Try to allocate a Linux map.
194
 *
195
 *  This function requires admin privileges.
196
 */
197
static int create_map_linux(const uint32_t map_type, const uint32_t key_size, const uint32_t value_size,
2,900✔
198
                            const uint32_t max_entries, const ebpf_verifier_options_t options) {
199
    if (options.mock_map_fds) {
2,900✔
200
        const EbpfMapType type = get_map_type_linux(map_type);
2,900✔
201
        return create_map_crab(type, key_size, value_size, max_entries, options);
2,900✔
202
    }
2,900✔
203

204
#if __linux__
205
    union bpf_attr attr {};
×
206
    memset(&attr, '\0', sizeof(attr));
×
207
    attr.map_type = map_type;
×
208
    attr.key_size = key_size;
×
209
    attr.value_size = value_size;
×
210
    attr.max_entries = 20;
×
211
    attr.map_flags = map_type == BPF_MAP_TYPE_HASH ? BPF_F_NO_PREALLOC : 0;
×
212
    const int map_fd = do_bpf(BPF_MAP_CREATE, attr);
×
213
    if (map_fd < 0) {
×
214
        std::cerr << "Failed to create map, " << strerror(errno) << "\n";
×
UNCOV
215
        std::cerr << "Map: \n"
×
216
                  << " map_type = " << attr.map_type << "\n"
×
217
                  << " key_size = " << attr.key_size << "\n"
×
218
                  << " value_size = " << attr.value_size << "\n"
×
219
                  << " max_entries = " << attr.max_entries << "\n"
×
220
                  << " map_flags = " << attr.map_flags << "\n";
×
221
        exit(2);
×
222
    }
223
    return map_fd;
224
#else
225
    throw std::runtime_error(std::string("cannot create a Linux map"));
226
#endif
227
}
228

229
EbpfMapDescriptor& get_map_descriptor_linux(const int map_fd) {
12,745✔
230
    // First check if we already have the map descriptor cached.
231
    EbpfMapDescriptor* map = find_map_descriptor(map_fd);
12,745✔
232
    if (map != nullptr) {
12,745✔
233
        return *map;
12,744✔
234
    }
235

236
    // This fd was not created from the maps section of an ELF file,
237
    // but it may be an fd created by an app before calling the verifier.
238
    // In this case, we would like to query the map descriptor info
239
    // (key size, value size) from the execution context, but this is
240
    // not yet supported on Linux.
241

242
    throw UnmarshalError("map_fd " + std::to_string(map_fd) + " not found");
2✔
243
}
244

245
const ebpf_platform_t g_ebpf_platform_linux = {get_program_type_linux,
246
                                               get_helper_prototype_linux,
247
                                               is_helper_usable_linux,
248
                                               sizeof(bpf_load_map_def),
249
                                               parse_maps_section_linux,
250
                                               get_map_descriptor_linux,
251
                                               get_map_type_linux,
252
                                               resolve_inner_map_references_linux,
253
                                               bpf_conformance_groups_t::default_groups |
254
                                                   bpf_conformance_groups_t::packet};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc