Skip to content

Commit

Permalink
Limit number of generated BPF programs
Browse files Browse the repository at this point in the history
In some cases (e.g. when using the "probe" builtin), the number of
generated BPF functions may be very large which may cause BPFtrace to
hang. This change prevents that by setting a limit on the number of
generated BPF functions. The limit can be changed using the
BPFTRACE_MAX_BPF_PROGS environment variable.
  • Loading branch information
viktormalik authored and fbs committed Feb 10, 2022
1 parent 5e45d61 commit 79ef3e0
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to
#### Added
- Add builtin function: `cgroup_path`
- [#2055](https://github.com/iovisor/bpftrace/pull/2055)
- Limit number of generated BPF programs
- [#2141](https://github.com/iovisor/bpftrace/pull/2141)

#### Changed
#### Deprecated
Expand Down
9 changes: 9 additions & 0 deletions docs/reference_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ ENVIRONMENT:
BPFTRACE_NO_CPP_DEMANGLE [default: 0] disable C++ symbol demangling
BPFTRACE_MAP_KEYS_MAX [default: 4096] max keys in a map
BPFTRACE_MAX_PROBES [default: 512] max number of probes bpftrace can attach to
BPFTRACE_MAX_BPF_PROGS [default: 512] max number of generated BPF programs
BPFTRACE_CACHE_USER_SYMBOLS [default: auto] enable user symbol cache
BPFTRACE_VMLINUX [default: none] vmlinux path used for kernel symbol resolution
BPFTRACE_BTF [default: none] BTF file
Expand Down Expand Up @@ -530,6 +531,14 @@ If you're getting a lot of dropped events bpftrace may not be processing events
fast enough. It may be useful to bump the value higher so more events can be queued up. The tradeoff
is that bpftrace will use more memory.

### 9.9 `BPFTRACE_MAX_BPF_PROGS`

Default: 512

This is the maximum number of BPF programs (functions) that bpftrace can generate.
The main purpose of this limit is to prevent bpftrace from hanging since generating a lot of probes
takes a lot of resources (and it should not happen often).

## 10. Clang Environment Variables

bpftrace parses header files using libclang, the C interface to Clang. Thus environment variables
Expand Down
8 changes: 8 additions & 0 deletions man/adoc/bpftrace.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,14 @@ If you're getting a lot of dropped events bpftrace may not be processing events
It may be useful to bump the value higher so more events can be queued up.
The tradeoff is that bpftrace will use more memory.

=== BPFTRACE_MAX_BPF_PROGS

Default: 512

This is the maximum number of BPF programs (functions) that bpftrace can generate.
The main purpose of this limit is to prevent bpftrace from hanging since generating a lot of probes
takes a lot of resources (and it should not happen often).

////
!
!
Expand Down
12 changes: 12 additions & 0 deletions src/ast/passes/codegen_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2281,6 +2281,18 @@ void CodegenLLVM::visit(Probe &probe)
matches = bpftrace_.probe_matcher_->get_matches_for_ap(*attach_point);
}

probe_count_ += matches.size();
if (probe_count_ > bpftrace_.max_programs_)
{
throw std::runtime_error(
"Your program is trying to generate more than " +
std::to_string(probe_count_) +
" BPF programs, which exceeds the current limit of " +
std::to_string(bpftrace_.max_programs_) +
".\nYou can increase the limit through the BPFTRACE_MAX_BPF_PROGS "
"environment variable.");
}

tracepoint_struct_ = "";
for (const auto &m : matches)
{
Expand Down
1 change: 1 addition & 0 deletions src/ast/passes/codegen_llvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ class CodegenLLVM : public Visitor
AttachPoint *current_attach_point_ = nullptr;
std::string probefull_;
std::string tracepoint_struct_;
uint64_t probe_count_ = 0;
std::map<std::string, int> next_probe_index_;
// Used if there are duplicate USDT entries
int current_usdt_location_index_{ 0 };
Expand Down
1 change: 1 addition & 0 deletions src/bpftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ class BPFtrace
uint64_t mapmax_ = 4096;
size_t cat_bytes_max_ = 10240;
uint64_t max_probes_ = 512;
uint64_t max_programs_ = 512;
uint64_t log_size_ = 1000000;
uint64_t perf_rb_pages_ = 64;
uint64_t max_type_res_iterations = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ void usage()
std::cerr << " BPFTRACE_MAP_KEYS_MAX [default: 4096] max keys in a map" << std::endl;
std::cerr << " BPFTRACE_CAT_BYTES_MAX [default: 10k] maximum bytes read by cat builtin" << std::endl;
std::cerr << " BPFTRACE_MAX_PROBES [default: 512] max number of probes" << std::endl;
std::cerr << " BPFTRACE_MAX_BPF_PROGS [default: 512] max number of generated BPF programs" << std::endl;
std::cerr << " BPFTRACE_LOG_SIZE [default: 1000000] log size in bytes" << std::endl;
std::cerr << " BPFTRACE_PERF_RB_PAGES [default: 64] pages per CPU to allocate for ring buffer" << std::endl;
std::cerr << " BPFTRACE_NO_USER_SYMBOLS [default: 0] disable user symbol resolution" << std::endl;
Expand Down Expand Up @@ -266,6 +267,9 @@ static std::optional<struct timespec> get_boottime()
if (!get_uint64_env_var("BPFTRACE_MAX_PROBES", bpftrace.max_probes_))
return false;

if (!get_uint64_env_var("BPFTRACE_MAX_BPF_PROGS", bpftrace.max_programs_))
return false;

if (!get_uint64_env_var("BPFTRACE_LOG_SIZE", bpftrace.log_size_))
return false;

Expand Down
8 changes: 8 additions & 0 deletions tests/runtime/probe
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,11 @@ NAME END_processing_after_exit
PROG interval:s:1 { exit(); } END { printf("end"); }
EXPECT end
TIMEOUT 2

# The "probe" builtin forces bpftrace to generate one BPF function for each
# match and so we should fail on exceeding BPFTRACE_MAX_BPF_PROGS.
NAME bpf_programs_limit
PROG k:* { @[probe] = count(); }
EXPECT BPFTRACE_MAX_BPF_PROGS
WILL_FAIL
TIMEOUT 2

0 comments on commit 79ef3e0

Please sign in to comment.