rbbcc 0.11.6 → 0.11.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/rbbcc/version.rb +1 -1
- data/rbbcc.gemspec +5 -2
- metadata +2 -62
- data/docs/README.md +0 -7
- data/docs/answers/01-hello-world.rb +0 -16
- data/docs/answers/02-sys_sync.rb +0 -18
- data/docs/answers/03-hello_fields.rb +0 -33
- data/docs/answers/04-sync_timing.rb +0 -46
- data/docs/answers/05-sync_count.rb +0 -54
- data/docs/answers/06-disksnoop.rb +0 -71
- data/docs/answers/07-hello_perf_output.rb +0 -59
- data/docs/answers/08-sync_perf_output.rb +0 -60
- data/docs/answers/09-bitehist.rb +0 -32
- data/docs/answers/10-disklatency.rb +0 -51
- data/docs/answers/11-vfsreadlat.c +0 -46
- data/docs/answers/11-vfsreadlat.rb +0 -66
- data/docs/answers/12-urandomread.rb +0 -38
- data/docs/answers/13-disksnoop_fixed.rb +0 -108
- data/docs/answers/14-strlen_count.rb +0 -46
- data/docs/answers/15-nodejs_http_server.rb +0 -44
- data/docs/answers/16-task_switch.c +0 -23
- data/docs/answers/16-task_switch.rb +0 -17
- data/docs/answers/node-server.js +0 -11
- data/docs/getting_started.md +0 -154
- data/docs/projects_using_rbbcc.md +0 -43
- data/docs/tutorial_bcc_ruby_developer.md +0 -774
- data/docs/tutorial_bcc_ruby_developer_japanese.md +0 -770
- data/examples/bitehist.rb +0 -46
- data/examples/charty/Gemfile +0 -11
- data/examples/charty/Gemfile.lock +0 -48
- data/examples/charty/bitehist-unicode.rb +0 -87
- data/examples/collectsyscall.rb +0 -182
- data/examples/dddos.rb +0 -112
- data/examples/disksnoop.rb +0 -73
- data/examples/dns_blocker.rb +0 -134
- data/examples/example.gif +0 -0
- data/examples/extract_arg.rb +0 -26
- data/examples/hello_fields.rb +0 -32
- data/examples/hello_perf_output.rb +0 -64
- data/examples/hello_ring_buffer.rb +0 -64
- data/examples/hello_world.rb +0 -6
- data/examples/kvm_hypercall.rb +0 -69
- data/examples/lsm_sockblock.rb +0 -141
- data/examples/mallocstack.rb +0 -63
- data/examples/networking/http_filter/http-parse-simple.c +0 -114
- data/examples/networking/http_filter/http-parse-simple.rb +0 -85
- data/examples/pin_maps_a.rb +0 -88
- data/examples/pin_maps_b.rb +0 -71
- data/examples/py-orig/sockblock.py +0 -119
- data/examples/ringbuf_pin_a.rb +0 -51
- data/examples/ringbuf_pin_b.rb +0 -29
- data/examples/ruby_usdt.rb +0 -105
- data/examples/sbrk_trace.rb +0 -204
- data/examples/ssl_http_trace.rb +0 -274
- data/examples/syscalluname.rb +0 -39
- data/examples/table.rb +0 -15
- data/examples/tools/bashreadline.rb +0 -83
- data/examples/tools/execsnoop.rb +0 -229
- data/examples/tools/runqlat.rb +0 -148
- data/examples/urandomread-explicit.rb +0 -58
- data/examples/urandomread.rb +0 -39
- data/examples/usdt-test.rb +0 -6
- data/examples/usdt.rb +0 -26
data/examples/extract_arg.rb
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require 'rbbcc'
|
|
4
|
-
include RbBCC
|
|
5
|
-
|
|
6
|
-
code = <<CLANG
|
|
7
|
-
#include <uapi/linux/ptrace.h>
|
|
8
|
-
#define ARGSIZE 128
|
|
9
|
-
|
|
10
|
-
// must be syscall__${the_name} ?
|
|
11
|
-
int syscall__execve(struct pt_regs *ctx,
|
|
12
|
-
const char __user *filename,
|
|
13
|
-
const char __user *const __user *__argv,
|
|
14
|
-
const char __user *const __user *__envp)
|
|
15
|
-
{
|
|
16
|
-
char buf[ARGSIZE] = {};
|
|
17
|
-
bpf_probe_read(buf, sizeof(buf), (void *)filename);
|
|
18
|
-
bpf_trace_printk("execve: %s\\n", &buf);
|
|
19
|
-
|
|
20
|
-
return 0;
|
|
21
|
-
}
|
|
22
|
-
CLANG
|
|
23
|
-
|
|
24
|
-
b = BCC.new(text: code)
|
|
25
|
-
b.attach_kprobe(event: b.get_syscall_fnname("execve"), fn_name: "syscall__execve")
|
|
26
|
-
b.trace_print
|
data/examples/hello_fields.rb
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# This is a Hello World example that formats output as fields.
|
|
4
|
-
|
|
5
|
-
require 'rbbcc'
|
|
6
|
-
include RbBCC
|
|
7
|
-
|
|
8
|
-
# define BPF program
|
|
9
|
-
prog = <<CLANG
|
|
10
|
-
int hello(void *ctx) {
|
|
11
|
-
bpf_trace_printk("Hello, World!\\n");
|
|
12
|
-
return 0;
|
|
13
|
-
}
|
|
14
|
-
CLANG
|
|
15
|
-
|
|
16
|
-
# load BPF program
|
|
17
|
-
b = BCC.new(text: prog)
|
|
18
|
-
b.attach_kprobe(event: b.get_syscall_fnname("clone"), fn_name: "hello")
|
|
19
|
-
|
|
20
|
-
# header
|
|
21
|
-
puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "MESSAGE"])
|
|
22
|
-
|
|
23
|
-
# format output
|
|
24
|
-
loop do
|
|
25
|
-
begin
|
|
26
|
-
b.trace_fields do |task, pid, cpu, flags, ts, msg|
|
|
27
|
-
puts("%-18.9f %-16s %-6d %s" % [ts, task, pid, msg])
|
|
28
|
-
end
|
|
29
|
-
rescue Interrupt
|
|
30
|
-
exit
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# This is a Hello World example that uses BPF_PERF_OUTPUT.
|
|
4
|
-
# Ported from hello_perf_output.py
|
|
5
|
-
|
|
6
|
-
require 'rbbcc'
|
|
7
|
-
include RbBCC
|
|
8
|
-
|
|
9
|
-
# define BPF program
|
|
10
|
-
prog = """
|
|
11
|
-
#include <linux/sched.h>
|
|
12
|
-
|
|
13
|
-
// define output data structure in C
|
|
14
|
-
struct data_t {
|
|
15
|
-
u32 pid;
|
|
16
|
-
u64 ts;
|
|
17
|
-
char comm[TASK_COMM_LEN];
|
|
18
|
-
};
|
|
19
|
-
BPF_PERF_OUTPUT(events);
|
|
20
|
-
|
|
21
|
-
int hello(struct pt_regs *ctx) {
|
|
22
|
-
struct data_t data = {};
|
|
23
|
-
|
|
24
|
-
data.pid = bpf_get_current_pid_tgid();
|
|
25
|
-
data.ts = bpf_ktime_get_ns();
|
|
26
|
-
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
|
27
|
-
|
|
28
|
-
events.perf_submit(ctx, &data, sizeof(data));
|
|
29
|
-
|
|
30
|
-
return 0;
|
|
31
|
-
}
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
# load BPF program
|
|
35
|
-
b = BCC.new(text: prog)
|
|
36
|
-
b.attach_kprobe(event: b.get_syscall_fnname("clone"), fn_name: "hello")
|
|
37
|
-
|
|
38
|
-
# header
|
|
39
|
-
puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "MESSAGE"])
|
|
40
|
-
|
|
41
|
-
# process event
|
|
42
|
-
start = 0
|
|
43
|
-
print_event = lambda { |cpu, data, size|
|
|
44
|
-
event = b["events"].event(data)
|
|
45
|
-
if start == 0
|
|
46
|
-
start = event.ts
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
time_s = ((event.ts - start).to_f) / 1000000000
|
|
50
|
-
# event.comm.pack("c*").sprit
|
|
51
|
-
puts("%-18.9f %-16s %-6d %s" % [time_s, event.comm, event.pid,
|
|
52
|
-
"Hello, perf_output!"])
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
# loop with callback to print_event
|
|
56
|
-
b["events"].open_perf_buffer(&print_event)
|
|
57
|
-
|
|
58
|
-
loop do
|
|
59
|
-
begin
|
|
60
|
-
b.perf_buffer_poll()
|
|
61
|
-
rescue Interrupt
|
|
62
|
-
exit()
|
|
63
|
-
end
|
|
64
|
-
end
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# This is a Hello World example that uses BPF_PERF_OUTPUT.
|
|
4
|
-
# Ported from hello_perf_output.py
|
|
5
|
-
|
|
6
|
-
require 'rbbcc'
|
|
7
|
-
include RbBCC
|
|
8
|
-
|
|
9
|
-
# define BPF program
|
|
10
|
-
prog = """
|
|
11
|
-
#include <linux/sched.h>
|
|
12
|
-
|
|
13
|
-
struct data_t {
|
|
14
|
-
u32 pid;
|
|
15
|
-
u64 ts;
|
|
16
|
-
char comm[TASK_COMM_LEN];
|
|
17
|
-
};
|
|
18
|
-
BPF_RINGBUF_OUTPUT(buffer, 1 << 4);
|
|
19
|
-
|
|
20
|
-
int hello(struct pt_regs *ctx) {
|
|
21
|
-
struct data_t data = {};
|
|
22
|
-
|
|
23
|
-
data.pid = bpf_get_current_pid_tgid();
|
|
24
|
-
data.ts = bpf_ktime_get_ns();
|
|
25
|
-
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
|
26
|
-
|
|
27
|
-
buffer.ringbuf_output(&data, sizeof(data), 0);
|
|
28
|
-
|
|
29
|
-
return 0;
|
|
30
|
-
}
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
# load BPF program
|
|
34
|
-
b = BCC.new(text: prog)
|
|
35
|
-
b.attach_kprobe(event: b.get_syscall_fnname("clone"), fn_name: "hello")
|
|
36
|
-
|
|
37
|
-
# header
|
|
38
|
-
puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "MESSAGE"])
|
|
39
|
-
|
|
40
|
-
# process event
|
|
41
|
-
start = 0
|
|
42
|
-
print_event = lambda { |ctx, data, size|
|
|
43
|
-
event = b["buffer"].event(data)
|
|
44
|
-
if start == 0
|
|
45
|
-
start = event.ts
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
time_s = ((event.ts - start).to_f) / 1000000000
|
|
49
|
-
# event.comm.pack("c*").sprit
|
|
50
|
-
puts("%-18.9f %-16s %-6d %s" % [time_s, event.comm, event.pid,
|
|
51
|
-
"Hello, ringbuf!"])
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
# loop with callback to print_event
|
|
55
|
-
b["buffer"].open_ring_buffer(&print_event)
|
|
56
|
-
|
|
57
|
-
loop do
|
|
58
|
-
begin
|
|
59
|
-
b.ring_buffer_poll()
|
|
60
|
-
sleep(0.5)
|
|
61
|
-
rescue Interrupt
|
|
62
|
-
exit()
|
|
63
|
-
end
|
|
64
|
-
end
|
data/examples/hello_world.rb
DELETED
data/examples/kvm_hypercall.rb
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/python
|
|
2
|
-
#
|
|
3
|
-
# kvm_hypercall.rb - TODO: it is still not tested
|
|
4
|
-
# See original kvm_hypercall.py and txt
|
|
5
|
-
#
|
|
6
|
-
# Demonstrates stateful kvm_entry and kvm_exit recording along with the
|
|
7
|
-
# associated hypercall when exit_reason is VMCALL. See kvm_hypercall.txt
|
|
8
|
-
# for usage
|
|
9
|
-
#
|
|
10
|
-
# REQUIRES: Linux 4.7+ (BPF_PROG_TYPE_TRACEPOINT support)
|
|
11
|
-
#
|
|
12
|
-
# Copyright (c) 2017 ShiftLeft Inc.
|
|
13
|
-
#
|
|
14
|
-
# Author(s):
|
|
15
|
-
# Suchakrapani Sharma <suchakra@shiftleft.io>
|
|
16
|
-
|
|
17
|
-
require 'rbbcc'
|
|
18
|
-
include RbBCC
|
|
19
|
-
|
|
20
|
-
# load BPF program
|
|
21
|
-
b = BCC.new(text: <<CLANG)
|
|
22
|
-
#define EXIT_REASON 18
|
|
23
|
-
BPF_HASH(start, u8, u8);
|
|
24
|
-
|
|
25
|
-
TRACEPOINT_PROBE(kvm, kvm_exit) {
|
|
26
|
-
u8 e = EXIT_REASON;
|
|
27
|
-
u8 one = 1;
|
|
28
|
-
if (args->exit_reason == EXIT_REASON) {
|
|
29
|
-
bpf_trace_printk("KVM_EXIT exit_reason : %d\\n", args->exit_reason);
|
|
30
|
-
start.update(&e, &one);
|
|
31
|
-
}
|
|
32
|
-
return 0;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
TRACEPOINT_PROBE(kvm, kvm_entry) {
|
|
36
|
-
u8 e = EXIT_REASON;
|
|
37
|
-
u8 zero = 0;
|
|
38
|
-
u8 *s = start.lookup(&e);
|
|
39
|
-
if (s != NULL && *s == 1) {
|
|
40
|
-
bpf_trace_printk("KVM_ENTRY vcpu_id : %u\\n", args->vcpu_id);
|
|
41
|
-
start.update(&e, &zero);
|
|
42
|
-
}
|
|
43
|
-
return 0;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
TRACEPOINT_PROBE(kvm, kvm_hypercall) {
|
|
47
|
-
u8 e = EXIT_REASON;
|
|
48
|
-
u8 zero = 0;
|
|
49
|
-
u8 *s = start.lookup(&e);
|
|
50
|
-
if (s != NULL && *s == 1) {
|
|
51
|
-
bpf_trace_printk("HYPERCALL nr : %d\\n", args->nr);
|
|
52
|
-
}
|
|
53
|
-
return 0;
|
|
54
|
-
};
|
|
55
|
-
CLANG
|
|
56
|
-
|
|
57
|
-
# header
|
|
58
|
-
puts("%-18s %-16s %-6s %s" % ["TIME(s)", "COMM", "PID", "EVENT"])
|
|
59
|
-
|
|
60
|
-
# format output
|
|
61
|
-
loop do
|
|
62
|
-
begin
|
|
63
|
-
b.trace_fields do |task, pid, cpu, flags, ts, msg|
|
|
64
|
-
puts("%-18.9f %-16s %-6d %s" % [ts, task, pid, msg])
|
|
65
|
-
end
|
|
66
|
-
rescue Interrupt
|
|
67
|
-
exit
|
|
68
|
-
end
|
|
69
|
-
end
|
data/examples/lsm_sockblock.rb
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# lsm_sockblock.rb Monitor/block AF_ALG socket_create via BPF LSM.
|
|
4
|
-
#
|
|
5
|
-
# This example uses LSM_PROBE(socket_create) and a BPF_ARRAY map for mode:
|
|
6
|
-
# 0 = preview (log only)
|
|
7
|
-
# 1 = block (return -EPERM)
|
|
8
|
-
#
|
|
9
|
-
# The config map is pinned to bpffs so mode can be changed externally.
|
|
10
|
-
#
|
|
11
|
-
# Usage:
|
|
12
|
-
# sudo ruby examples/lsm_sockblock.rb
|
|
13
|
-
# sudo ruby examples/lsm_sockblock.rb --mode block
|
|
14
|
-
# sudo ruby examples/lsm_sockblock.rb --pin-path /sys/fs/bpf/my_config_map
|
|
15
|
-
|
|
16
|
-
require 'optparse'
|
|
17
|
-
require 'socket'
|
|
18
|
-
require 'rbbcc'
|
|
19
|
-
|
|
20
|
-
include RbBCC
|
|
21
|
-
|
|
22
|
-
PROGRAM = <<~CLANG
|
|
23
|
-
#include <linux/socket.h>
|
|
24
|
-
#include <uapi/asm-generic/errno-base.h>
|
|
25
|
-
|
|
26
|
-
struct data_t {
|
|
27
|
-
u32 pid;
|
|
28
|
-
int family;
|
|
29
|
-
int type;
|
|
30
|
-
int is_warning;
|
|
31
|
-
int is_blocked;
|
|
32
|
-
char comm[16];
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
BPF_PERF_OUTPUT(events);
|
|
36
|
-
BPF_ARRAY(config_map, u32, 1);
|
|
37
|
-
|
|
38
|
-
LSM_PROBE(socket_create, int family, int type, int protocol, int kern)
|
|
39
|
-
{
|
|
40
|
-
u32 pid = bpf_get_current_pid_tgid() >> 32;
|
|
41
|
-
struct data_t data = {};
|
|
42
|
-
|
|
43
|
-
u32 key = 0;
|
|
44
|
-
u32 *mode = config_map.lookup(&key);
|
|
45
|
-
int is_block_mode = (mode && *mode == 1);
|
|
46
|
-
|
|
47
|
-
data.pid = pid;
|
|
48
|
-
data.family = family;
|
|
49
|
-
data.type = type;
|
|
50
|
-
bpf_get_current_comm(&data.comm, sizeof(data.comm));
|
|
51
|
-
|
|
52
|
-
if (family == AF_ALG) {
|
|
53
|
-
data.is_blocked = is_block_mode;
|
|
54
|
-
data.is_warning = 1;
|
|
55
|
-
events.perf_submit(ctx, &data, sizeof(data));
|
|
56
|
-
|
|
57
|
-
if (is_block_mode) {
|
|
58
|
-
return -EPERM;
|
|
59
|
-
}
|
|
60
|
-
} else {
|
|
61
|
-
data.is_blocked = 0;
|
|
62
|
-
data.is_warning = 0;
|
|
63
|
-
events.perf_submit(ctx, &data, sizeof(data));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return 0;
|
|
67
|
-
}
|
|
68
|
-
CLANG
|
|
69
|
-
|
|
70
|
-
options = {
|
|
71
|
-
mode: "preview",
|
|
72
|
-
pin_path: "/sys/fs/bpf/rbbcc_lsm_config_map"
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
OptionParser.new do |opts|
|
|
76
|
-
opts.banner = "Usage: #{$0} [--mode preview|block] [--pin-path PATH]"
|
|
77
|
-
|
|
78
|
-
opts.on("--mode MODE", ["preview", "block"], "Operation mode (default: preview)") do |v|
|
|
79
|
-
options[:mode] = v
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
opts.on("--pin-path PATH", "bpffs pin path (default: /sys/fs/bpf/rbbcc_lsm_config_map)") do |v|
|
|
83
|
-
options[:pin_path] = v
|
|
84
|
-
end
|
|
85
|
-
end.parse!
|
|
86
|
-
|
|
87
|
-
mode_value = (options[:mode] == "block") ? 1 : 0
|
|
88
|
-
|
|
89
|
-
families = Socket.constants.grep(/^AF_/).each_with_object({}) do |name, h|
|
|
90
|
-
begin
|
|
91
|
-
v = Socket.const_get(name)
|
|
92
|
-
h[v] = name.to_s if v.is_a?(Integer)
|
|
93
|
-
rescue NameError
|
|
94
|
-
next
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
types = Socket.constants.grep(/^SOCK_/).each_with_object({}) do |name, h|
|
|
99
|
-
begin
|
|
100
|
-
v = Socket.const_get(name)
|
|
101
|
-
h[v] = name.to_s if v.is_a?(Integer)
|
|
102
|
-
rescue NameError
|
|
103
|
-
next
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
begin
|
|
108
|
-
b = BCC.new(text: PROGRAM)
|
|
109
|
-
|
|
110
|
-
config = b["config_map"]
|
|
111
|
-
config[0] = mode_value
|
|
112
|
-
|
|
113
|
-
File.unlink(options[:pin_path]) if File.exist?(options[:pin_path])
|
|
114
|
-
BCC.pin!(config.map_fd, options[:pin_path])
|
|
115
|
-
|
|
116
|
-
puts "LSM BPF started in #{options[:mode].upcase} mode."
|
|
117
|
-
puts "Pinned config map: #{options[:pin_path]}"
|
|
118
|
-
puts "Tracing AF_ALG socket_create... Press Ctrl-C to exit."
|
|
119
|
-
|
|
120
|
-
b["events"].open_perf_buffer do |cpu, data, size|
|
|
121
|
-
event = b["events"].event(data)
|
|
122
|
-
family = families.fetch(event.family, "AF_UNKNOWN(#{event.family})")
|
|
123
|
-
stype = types.fetch(event.type, "SOCK_UNKNOWN(#{event.type})")
|
|
124
|
-
|
|
125
|
-
puts "PID: #{event.pid.to_s.ljust(7)} | COMM: #{event.comm.to_s.ljust(15)} | FAMILY: #{family.ljust(14)} | TYPE: #{stype}"
|
|
126
|
-
|
|
127
|
-
next if event.is_warning == 0
|
|
128
|
-
|
|
129
|
-
mode_str = (event.is_blocked == 1) ? "BLOCK" : "PREVIEW"
|
|
130
|
-
status = (event.is_blocked == 1) ? "REJECTED" : "WARNING"
|
|
131
|
-
puts "\e[1;31m[#{mode_str}] #{status}: PID #{event.pid} (#{event.comm}) tried AF_ALG socket creation.\e[0m"
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
loop do
|
|
135
|
-
b.perf_buffer_poll
|
|
136
|
-
end
|
|
137
|
-
rescue Interrupt
|
|
138
|
-
puts "\nStopping..."
|
|
139
|
-
ensure
|
|
140
|
-
File.unlink(options[:pin_path]) if File.exist?(options[:pin_path])
|
|
141
|
-
end
|
data/examples/mallocstack.rb
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
# mallocstacks Trace malloc() calls in a process and print the full
|
|
4
|
-
# stack trace for all callsites.
|
|
5
|
-
# For Linux, uses BCC, eBPF. Embedded C.
|
|
6
|
-
#
|
|
7
|
-
# This script is a basic example of the new Linux 4.6+ BPF_STACK_TRACE
|
|
8
|
-
# table API.
|
|
9
|
-
#
|
|
10
|
-
# Copyright 2016 GitHub, Inc.
|
|
11
|
-
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
12
|
-
|
|
13
|
-
require 'rbbcc'
|
|
14
|
-
include RbBCC
|
|
15
|
-
|
|
16
|
-
if ARGV.size == 0
|
|
17
|
-
$stderr.puts("USAGE: mallocstacks PID")
|
|
18
|
-
exit
|
|
19
|
-
end
|
|
20
|
-
pid = ARGV[0].to_i
|
|
21
|
-
|
|
22
|
-
# load BPF program
|
|
23
|
-
b = BCC.new(text: <<CLANG)
|
|
24
|
-
#include <uapi/linux/ptrace.h>
|
|
25
|
-
|
|
26
|
-
BPF_HASH(calls, int);
|
|
27
|
-
BPF_STACK_TRACE(stack_traces, 1024);
|
|
28
|
-
|
|
29
|
-
int alloc_enter(struct pt_regs *ctx, size_t size) {
|
|
30
|
-
int key = stack_traces.get_stackid(ctx,
|
|
31
|
-
BPF_F_USER_STACK|BPF_F_REUSE_STACKID);
|
|
32
|
-
if (key < 0)
|
|
33
|
-
return 0;
|
|
34
|
-
|
|
35
|
-
// could also use `calls.increment(key, size);`
|
|
36
|
-
u64 zero = 0, *val;
|
|
37
|
-
val = calls.lookup_or_init(&key, &zero);
|
|
38
|
-
if (val)
|
|
39
|
-
(*val) += size;
|
|
40
|
-
return 0;
|
|
41
|
-
};
|
|
42
|
-
CLANG
|
|
43
|
-
|
|
44
|
-
b.attach_uprobe(name: "c", sym: "malloc", fn_name: "alloc_enter", pid: pid)
|
|
45
|
-
puts("Attaching to malloc in pid %d, Ctrl+C to quit." % pid)
|
|
46
|
-
|
|
47
|
-
# sleep until Ctrl-C
|
|
48
|
-
loop do
|
|
49
|
-
begin
|
|
50
|
-
sleep 1
|
|
51
|
-
rescue Interrupt
|
|
52
|
-
break # pass
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
calls = b.get_table("calls")
|
|
56
|
-
stack_traces = b.get_table("stack_traces")
|
|
57
|
-
|
|
58
|
-
calls.items.sort_by{|k, v| v.to_bcc_value }.reverse.each do |(k, v)|
|
|
59
|
-
puts("%d bytes allocated at:" % v.to_bcc_value)
|
|
60
|
-
stack_traces.walk(k) do |addr|
|
|
61
|
-
puts("\t%s" % BCC.sym(addr, pid, show_offset: true))
|
|
62
|
-
end
|
|
63
|
-
end
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
#include <uapi/linux/ptrace.h>
|
|
2
|
-
#include <net/sock.h>
|
|
3
|
-
#include <bcc/proto.h>
|
|
4
|
-
|
|
5
|
-
#define IP_TCP 6
|
|
6
|
-
#define ETH_HLEN 14
|
|
7
|
-
|
|
8
|
-
/*eBPF program.
|
|
9
|
-
Filter IP and TCP packets, having payload not empty
|
|
10
|
-
and containing "HTTP", "GET", "POST" ... as first bytes of payload
|
|
11
|
-
if the program is loaded as PROG_TYPE_SOCKET_FILTER
|
|
12
|
-
and attached to a socket
|
|
13
|
-
return 0 -> DROP the packet
|
|
14
|
-
return -1 -> KEEP the packet and return it to user space (userspace can read it from the socket_fd )
|
|
15
|
-
*/
|
|
16
|
-
int http_filter(struct __sk_buff *skb) {
|
|
17
|
-
|
|
18
|
-
u8 *cursor = 0;
|
|
19
|
-
|
|
20
|
-
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
|
|
21
|
-
//filter IP packets (ethernet type = 0x0800)
|
|
22
|
-
if (!(ethernet->type == 0x0800)) {
|
|
23
|
-
goto DROP;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
|
|
27
|
-
//filter TCP packets (ip next protocol = 0x06)
|
|
28
|
-
if (ip->nextp != IP_TCP) {
|
|
29
|
-
goto DROP;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
u32 tcp_header_length = 0;
|
|
33
|
-
u32 ip_header_length = 0;
|
|
34
|
-
u32 payload_offset = 0;
|
|
35
|
-
u32 payload_length = 0;
|
|
36
|
-
|
|
37
|
-
//calculate ip header length
|
|
38
|
-
//value to multiply * 4
|
|
39
|
-
//e.g. ip->hlen = 5 ; IP Header Length = 5 x 4 byte = 20 byte
|
|
40
|
-
ip_header_length = ip->hlen << 2; //SHL 2 -> *4 multiply
|
|
41
|
-
|
|
42
|
-
//check ip header length against minimum
|
|
43
|
-
if (ip_header_length < sizeof(*ip)) {
|
|
44
|
-
goto DROP;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
//shift cursor forward for dynamic ip header size
|
|
48
|
-
void *_ = cursor_advance(cursor, (ip_header_length-sizeof(*ip)));
|
|
49
|
-
|
|
50
|
-
struct tcp_t *tcp = cursor_advance(cursor, sizeof(*tcp));
|
|
51
|
-
|
|
52
|
-
//calculate tcp header length
|
|
53
|
-
//value to multiply *4
|
|
54
|
-
//e.g. tcp->offset = 5 ; TCP Header Length = 5 x 4 byte = 20 byte
|
|
55
|
-
tcp_header_length = tcp->offset << 2; //SHL 2 -> *4 multiply
|
|
56
|
-
|
|
57
|
-
//calculate payload offset and length
|
|
58
|
-
payload_offset = ETH_HLEN + ip_header_length + tcp_header_length;
|
|
59
|
-
payload_length = ip->tlen - ip_header_length - tcp_header_length;
|
|
60
|
-
|
|
61
|
-
//http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes
|
|
62
|
-
//minimum length of http request is always geater than 7 bytes
|
|
63
|
-
//avoid invalid access memory
|
|
64
|
-
//include empty payload
|
|
65
|
-
if(payload_length < 7) {
|
|
66
|
-
goto DROP;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
//load first 7 byte of payload into p (payload_array)
|
|
70
|
-
//direct access to skb not allowed
|
|
71
|
-
unsigned long p[7];
|
|
72
|
-
int i = 0;
|
|
73
|
-
for (i = 0; i < 7; i++) {
|
|
74
|
-
p[i] = load_byte(skb , payload_offset + i);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
//find a match with an HTTP message
|
|
78
|
-
//HTTP
|
|
79
|
-
if ((p[0] == 'H') && (p[1] == 'T') && (p[2] == 'T') && (p[3] == 'P')) {
|
|
80
|
-
goto KEEP;
|
|
81
|
-
}
|
|
82
|
-
//GET
|
|
83
|
-
if ((p[0] == 'G') && (p[1] == 'E') && (p[2] == 'T')) {
|
|
84
|
-
goto KEEP;
|
|
85
|
-
}
|
|
86
|
-
//POST
|
|
87
|
-
if ((p[0] == 'P') && (p[1] == 'O') && (p[2] == 'S') && (p[3] == 'T')) {
|
|
88
|
-
goto KEEP;
|
|
89
|
-
}
|
|
90
|
-
//PUT
|
|
91
|
-
if ((p[0] == 'P') && (p[1] == 'U') && (p[2] == 'T')) {
|
|
92
|
-
goto KEEP;
|
|
93
|
-
}
|
|
94
|
-
//DELETE
|
|
95
|
-
if ((p[0] == 'D') && (p[1] == 'E') && (p[2] == 'L') && (p[3] == 'E') && (p[4] == 'T') && (p[5] == 'E')) {
|
|
96
|
-
goto KEEP;
|
|
97
|
-
}
|
|
98
|
-
//HEAD
|
|
99
|
-
if ((p[0] == 'H') && (p[1] == 'E') && (p[2] == 'A') && (p[3] == 'D')) {
|
|
100
|
-
goto KEEP;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
//no HTTP match
|
|
104
|
-
goto DROP;
|
|
105
|
-
|
|
106
|
-
//keep the packet and send it to userspace retruning -1
|
|
107
|
-
KEEP:
|
|
108
|
-
return -1;
|
|
109
|
-
|
|
110
|
-
//drop the packet returning 0
|
|
111
|
-
DROP:
|
|
112
|
-
return 0;
|
|
113
|
-
|
|
114
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
#
|
|
3
|
-
#Original http-parse-simple.py in invisor/bcc
|
|
4
|
-
#Bertrone Matteo - Polytechnic of Turin
|
|
5
|
-
#November 2015
|
|
6
|
-
#Ruby version by Uchio Kondo, License follows
|
|
7
|
-
#
|
|
8
|
-
#eBPF application that parses HTTP packets
|
|
9
|
-
#and extracts (and prints on screen) the URL contained in the GET/POST request.
|
|
10
|
-
#
|
|
11
|
-
#eBPF program http_filter is used as SOCKET_FILTER attached to eth0 interface.
|
|
12
|
-
#only packet of type ip and tcp containing HTTP GET/POST are returned to userspace, others dropped
|
|
13
|
-
#
|
|
14
|
-
#python script uses bcc BPF Compiler Collection by iovisor (https://github.com/iovisor/bcc)
|
|
15
|
-
#and prints on stdout the first line of the HTTP GET/POST request containing the url
|
|
16
|
-
|
|
17
|
-
require 'rbbcc'
|
|
18
|
-
require 'socket'
|
|
19
|
-
require 'io/nonblock'
|
|
20
|
-
include RbBCC
|
|
21
|
-
|
|
22
|
-
def usage
|
|
23
|
-
puts <<-USAGE
|
|
24
|
-
USAGE: #{$0} [-i <if_name>]
|
|
25
|
-
USAGE
|
|
26
|
-
exit
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
interface = "eth0"
|
|
30
|
-
|
|
31
|
-
if ARGV.size == 2
|
|
32
|
-
if ARGV[0] == '-i'
|
|
33
|
-
interface = ARGV[1]
|
|
34
|
-
else
|
|
35
|
-
usage
|
|
36
|
-
end
|
|
37
|
-
elsif ARGV.size != 0
|
|
38
|
-
usage
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
puts("binding socket to '%s'" % interface)
|
|
42
|
-
|
|
43
|
-
bpf = BCC.new(src_file: "http-parse-simple.c")
|
|
44
|
-
|
|
45
|
-
function_http_filter = bpf.load_func("http_filter", BPF::SOCKET_FILTER)
|
|
46
|
-
|
|
47
|
-
BCC.attach_raw_socket(function_http_filter, interface)
|
|
48
|
-
|
|
49
|
-
socket_fd = function_http_filter[:sock]
|
|
50
|
-
|
|
51
|
-
sock = Socket.for_fd socket_fd
|
|
52
|
-
sock.nonblock = false
|
|
53
|
-
|
|
54
|
-
ETH_HLEN = 14
|
|
55
|
-
loop do
|
|
56
|
-
packet_str = sock.sysread(2048)
|
|
57
|
-
packet_bytearray = packet_str.bytes
|
|
58
|
-
|
|
59
|
-
# See original comment...
|
|
60
|
-
#calculate packet total length
|
|
61
|
-
total_length = packet_bytearray[ETH_HLEN + 2] #load MSB
|
|
62
|
-
total_length = total_length << 8 #shift MSB
|
|
63
|
-
total_length = total_length + packet_bytearray[ETH_HLEN + 3] #add LSB
|
|
64
|
-
|
|
65
|
-
#calculate ip header length
|
|
66
|
-
ip_header_length = packet_bytearray[ETH_HLEN] #load Byte
|
|
67
|
-
ip_header_length = ip_header_length & 0x0F #mask bits 0..3
|
|
68
|
-
ip_header_length = ip_header_length << 2 #shift to obtain length
|
|
69
|
-
|
|
70
|
-
tcp_header_length = packet_bytearray[ETH_HLEN + ip_header_length + 12] #load Byte
|
|
71
|
-
tcp_header_length = tcp_header_length & 0xF0 #mask bit 4..7
|
|
72
|
-
tcp_header_length = tcp_header_length >> 2 #SHR 4 ; SHL 2 -> SHR 2
|
|
73
|
-
|
|
74
|
-
payload_offset = ETH_HLEN + ip_header_length + tcp_header_length
|
|
75
|
-
|
|
76
|
-
((payload_offset-1)..(packet_bytearray.size-1)).each do |i|
|
|
77
|
-
if packet_bytearray[i] == 0x0A
|
|
78
|
-
if packet_bytearray[i-1] == 0x0D
|
|
79
|
-
break
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
print(packet_bytearray[i].chr)
|
|
83
|
-
end
|
|
84
|
-
puts
|
|
85
|
-
end
|