-
Notifications
You must be signed in to change notification settings - Fork 165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(modern): try to address a page fault caused by bpf_probe_read_kernel
#1858
Changes from 1 commit
cdbd5ab
2a9f3c7
a5d1950
03e4ec2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,6 +73,29 @@ int BPF_PROG(socket_x, | |
/* Parameter 1: res (type: PT_ERRNO)*/ | ||
ringbuf__store_s64(&ringbuf, ret); | ||
|
||
/* Just called once by our scap process */ | ||
if(ret >= 0 && maps__get_socket_file_ops() == NULL) | ||
{ | ||
struct task_struct *task = get_current_task(); | ||
/* Please note that in `g_settings.scap_pid` scap will put its virtual pid | ||
* if it is running inside a container. If we want to extract the same information | ||
* in the kernel we need to extract the virtual pid of the task. | ||
*/ | ||
pid_t vpid = extract__task_xid_vnr(task, PIDTYPE_TGID); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since we can run inside a container we need to extract the |
||
/* it means that scap is performing the calibration */ | ||
if(vpid == maps__get_scap_pid()) | ||
{ | ||
struct file *f = extract__file_struct_from_fd(ret); | ||
if(f) | ||
{ | ||
struct file_operations *f_op = (struct file_operations *)BPF_CORE_READ(f, f_op); | ||
maps__set_socket_file_ops((void*)f_op); | ||
/* we need to rewrite the event header */ | ||
ringbuf__rewrite_header_for_calibration(&ringbuf, vpid); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. instead of using additional variables we can simply use our event to communicate something to userspace |
||
} | ||
} | ||
} | ||
|
||
/*=============================== COLLECT PARAMETERS ===========================*/ | ||
|
||
ringbuf__submit_event(&ringbuf); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ limitations under the License. | |
#include <errno.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <sys/socket.h> | ||
|
||
#define SCAP_HANDLE_T struct modern_bpf_engine | ||
#include <libscap/engine/modern_bpf/scap_modern_bpf.h> | ||
|
@@ -30,6 +31,7 @@ limitations under the License. | |
#include <sys/utsname.h> | ||
#include <libscap/ringbuffer/ringbuffer.h> | ||
#include <libscap/scap_engine_util.h> | ||
#include <libscap/strerror.h> | ||
|
||
static struct modern_bpf_engine* scap_modern_bpf__alloc_engine(scap_t* main_handle, char* lasterr_ptr) | ||
{ | ||
|
@@ -164,6 +166,74 @@ int32_t scap_modern_bpf__stop_capture(struct scap_engine_handle engine) | |
return pman_enforce_sc_set(NULL); | ||
} | ||
|
||
static int32_t calibrate_socket_file_ops(struct scap_engine_handle engine) | ||
{ | ||
/* Set the scap_pid for the socket calibration. | ||
* If we are in a container this is the virtual pid. | ||
*/ | ||
pid_t scap_pid = getpid(); | ||
pman_set_scap_pid(scap_pid); | ||
|
||
/* We just need to enable the socket syscall for the socket calibration */ | ||
engine.m_handle->curr_sc_set.ppm_sc[PPM_SC_SOCKET] = 1; | ||
if(scap_modern_bpf__start_capture(engine) != SCAP_SUCCESS) | ||
{ | ||
return scap_errprintf(engine.m_handle->m_lasterr, errno, "unable to start the capture for the socket calibration"); | ||
} | ||
|
||
int fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
if(fd == -1) | ||
{ | ||
return scap_errprintf(engine.m_handle->m_lasterr, errno, "unable to create a socket for the calibration"); | ||
} | ||
close(fd); | ||
|
||
/* We need to stop the capture */ | ||
if(scap_modern_bpf__stop_capture(engine) != SCAP_SUCCESS) | ||
{ | ||
return scap_errprintf(engine.m_handle->m_lasterr, errno, "unable to stop the capture after the calibration"); | ||
} | ||
|
||
/* We need to read the socket event from the buffer */ | ||
scap_evt* pevent = NULL; | ||
uint16_t attempts = 0; | ||
uint16_t buffer_id = 0; | ||
uint32_t flags = 0; | ||
int32_t res = 0; | ||
bool found = false; | ||
|
||
while(attempts <= 1) | ||
{ | ||
res = scap_modern_bpf__next(engine, &pevent, &buffer_id, &flags); | ||
if(res == SCAP_SUCCESS && pevent != NULL) | ||
{ | ||
/* This is not a socket event or this is not our socket event */ | ||
if(pevent->type != PPME_SOCKET_SOCKET_X || pevent->tid != scap_pid) | ||
{ | ||
continue; | ||
} | ||
|
||
/* BPF side we send this special event with nparams = 0 */ | ||
if(pevent->nparams == 0) | ||
{ | ||
/* We don't want to stop here because we want to clean all the buffers. */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we clean all the buffers so we will restart the capture in a clean state |
||
found = true; | ||
} | ||
} | ||
else if(res == SCAP_TIMEOUT) | ||
{ | ||
/* We need more than one attempt because the first time we just need to read the producers' positions. */ | ||
attempts++; | ||
} | ||
} | ||
|
||
if(!found) | ||
{ | ||
return scap_errprintf(engine.m_handle->m_lasterr, 0, "unable to find the socket event for the calibration in the ringbuffers"); | ||
} | ||
return SCAP_SUCCESS; | ||
} | ||
|
||
int32_t scap_modern_bpf__init(scap_t* handle, scap_open_args* oargs) | ||
{ | ||
int ret = 0; | ||
|
@@ -211,9 +281,6 @@ int32_t scap_modern_bpf__init(scap_t* handle, scap_open_args* oargs) | |
return ret; | ||
} | ||
|
||
/* Store interesting sc codes */ | ||
memcpy(&engine.m_handle->curr_sc_set, &oargs->ppm_sc_of_interest, sizeof(interesting_ppm_sc_set)); | ||
|
||
/* Set the boot time */ | ||
uint64_t boot_time = 0; | ||
if(scap_get_precise_boot_time(handle->m_lasterr, &boot_time) != SCAP_SUCCESS) | ||
|
@@ -222,6 +289,15 @@ int32_t scap_modern_bpf__init(scap_t* handle, scap_open_args* oargs) | |
} | ||
pman_set_boot_time(boot_time); | ||
|
||
/* Calibrate the socket at init time */ | ||
if(calibrate_socket_file_ops(engine) != SCAP_SUCCESS) | ||
{ | ||
return SCAP_FAILURE; | ||
} | ||
|
||
/* Store interesting sc codes */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. moved after the calibration so we will clear the |
||
memcpy(&engine.m_handle->curr_sc_set, &oargs->ppm_sc_of_interest, sizeof(interesting_ppm_sc_set)); | ||
|
||
engine.m_handle->m_api_version = pman_get_probe_api_ver(); | ||
engine.m_handle->m_schema_version = pman_get_probe_schema_ver(); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now this info is only in kernel space