-
-
Notifications
You must be signed in to change notification settings - Fork 84
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
Support read /sys/bus/event_source/devices/uprobe/type on old kernel versions #248
Conversation
/sys/bus/event_source/devices/uprobe/type was also accessed by libbpf, do you have any method to solve this? |
Yes,Since we can't modify libbpf directly, what I modify is the contents of runtime/syscall-server library. ld_preload can override the open function in libc to achieve the effect of modification at runtime, so as to solve this problem. |
|
||
return expanded_path; | ||
} else { | ||
fprintf(stderr, "Failed to allocate memory\n"); |
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.
Please use spdlog to print logs
if (home_dir != NULL) { | ||
// Allocate memory for the expanded path | ||
size_t len = strlen(home_dir) + strlen(path) - 1; // -1 to exclude ~ | ||
char *expanded_path = (char *)malloc(len + 1); // +1 for the null terminator |
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.
Is the buffer allocated here leaked?
I didn't see where you override the open function, will it be done in this PR? |
{ | ||
const char *home_dir = getenv("HOME"); | ||
if (home_dir == NULL) { | ||
SPDLOG_INFO("Error: HOME environment variable is not set"); |
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.
Should it be SPDLOG_ERROR
?
@@ -23,13 +23,17 @@ class syscall_context { | |||
using epoll_ctl_fn = int (*)(int, int, int, struct epoll_event *); | |||
using epoll_wait_fn = int (*)(int, struct epoll_event *, int, int); | |||
using munmap_fn = int (*)(void *, size_t); | |||
using fopen_fn = FILE *(*)(const char *,const char *); | |||
using open_fn = int (*)(const char *, int, ...); |
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.
Do we really need to override fopen? Doesn't fopen internally call open to open files?
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.
In fact, the internal call of fopen is the openat system call, but when the program calls fopen, it does not trigger some of the processing done by bpftime to openat.
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.
I did my tests on openat and didn't see that calling fopen would trigger some of the processing bpftime does for openat:
Set a breakpoint for handle_openat() as follows:
int syscall_context::handle_openat(int fd, const char *file, int oflag, unsigned short mode)
{
if (!enable_mock){
printf("1:%s\n",file);
return orig_openat_fn(fd, file, oflag, mode);
}
try_startup();
printf("2:%s\n",file);
const char * new_file = bpftime_checkfile(file);
printf("3:%s\n",new_file);
return orig_openat_fn(fd, new_file, oflag, mode);
}
Test procedure:
...
const char *filename = "/sys/bus/event_source/devices/uprobe/type";
FILE *file = fopen(filename, "r");
...
Tracing the program using strace found that fopen calls the openat system call:
...
openat(AT_FDCWD, "/sys/bus/event_source/devices/uprobe/type", O_RDONLY) = 3
...
Executing the commandLD_PRELOAD=build/runtime/syscall-server/libbpftime-syscall-server.so./test
produces the following output without firing the breakpoint:
[2024-03-12 10:00:50.742] [info] [syscall_context.hpp:93] manager constructed
Content: 9
Now change the test program to one that uses the openat function directly:
...
const char *directory = "/sys/bus/event_source/devices";
const char *filename = "uprobe/type";
int dir_fd = open(directory, O_RDONLY);
...
int file_fd = openat(dir_fd, filename, O_RDONLY);
...
Executing the command LD_PRELOAD=build/runtime/syscall-server/libbpftime-syscall-server.so./test
produces the following output, and you can see that the breakpoint is triggered:
[2024-03-12 10:03:29.609] [info] [syscall_context.hpp:93] manager constructed
[2024-03-12 10:03:29.609] [info] [syscall_server_utils.cpp:24] Initialize syscall server
[2024-03-12 10:03:29][info][26465] Global shm constructed. shm_open_type 0 for bpftime_maps_shm
[2024-03-12 10:03:29][info][26465] Enabling helper groups ufunc, kernel, shm_map by default
[2024-03-12 10:03:29][info][26465] bpftime-syscall-server started
2:uprobe/type
3:uprobe/type
Content: 9
INFO [26465]: Global shm destructed
Does bpftime only attach dynamic libraries to the surface of the program?
Another problem is that although this modified libbpf file access, but libbpf is actually want to get/sys/bus/event_source/devices/uprobe/type of value, and for low version of the kernel, the value is not exist, When libbpf gets the wrong value, it will also report an error (libbpf: prog 'do_count': failed to create uprobe '/lib/x86_64-linux-gnu/libc.so.6:0x9f920' perf event: Operation not permitted), when I changed the contents of the replacement file to the correct value, but the correct value does not exist for the lower kernel version, this method does not seem feasible.
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.
I did my tests on openat and didn't see that calling fopen would trigger some of the processing bpftime does for openat:
Set a breakpoint for handle_openat() as follows:
int syscall_context::handle_openat(int fd, const char *file, int oflag, unsigned short mode) { if (!enable_mock){ printf("1:%s\n",file); return orig_openat_fn(fd, file, oflag, mode); } try_startup(); printf("2:%s\n",file); const char * new_file = bpftime_checkfile(file); printf("3:%s\n",new_file); return orig_openat_fn(fd, new_file, oflag, mode); }
Test procedure:
... const char *filename = "/sys/bus/event_source/devices/uprobe/type"; FILE *file = fopen(filename, "r"); ...
Tracing the program using strace found that fopen calls the openat system call:
... openat(AT_FDCWD, "/sys/bus/event_source/devices/uprobe/type", O_RDONLY) = 3 ...
Executing the command
LD_PRELOAD=build/runtime/syscall-server/libbpftime-syscall-server.so./test
produces the following output without firing the breakpoint:[2024-03-12 10:00:50.742] [info] [syscall_context.hpp:93] manager constructed Content: 9
Now change the test program to one that uses the openat function directly:
... const char *directory = "/sys/bus/event_source/devices"; const char *filename = "uprobe/type"; int dir_fd = open(directory, O_RDONLY); ... int file_fd = openat(dir_fd, filename, O_RDONLY); ...
Executing the command
LD_PRELOAD=build/runtime/syscall-server/libbpftime-syscall-server.so./test
produces the following output, and you can see that the breakpoint is triggered:[2024-03-12 10:03:29.609] [info] [syscall_context.hpp:93] manager constructed [2024-03-12 10:03:29.609] [info] [syscall_server_utils.cpp:24] Initialize syscall server [2024-03-12 10:03:29][info][26465] Global shm constructed. shm_open_type 0 for bpftime_maps_shm [2024-03-12 10:03:29][info][26465] Enabling helper groups ufunc, kernel, shm_map by default [2024-03-12 10:03:29][info][26465] bpftime-syscall-server started 2:uprobe/type 3:uprobe/type Content: 9 INFO [26465]: Global shm destructed
Does bpftime only attach dynamic libraries to the surface of the program?
Another problem is that although this modified libbpf file access, but libbpf is actually want to get/sys/bus/event_source/devices/uprobe/type of value, and for low version of the kernel, the value is not exist, When libbpf gets the wrong value, it will also report an error (libbpf: prog 'do_count': failed to create uprobe '/lib/x86_64-linux-gnu/libc.so.6:0x9f920' perf event: Operation not permitted), when I changed the contents of the replacement file to the correct value, but the correct value does not exist for the lower kernel version, this method does not seem feasible.
LD_PRELOAD can only replace functions that were dynamically linked, you may see man ld.so
for details.
My hints for replacing statically linked functions: Use a linker script to manually override the linked function to a custom one. Is this practical?
@zhangzihengya Hi, how's going on now? |
The following logic should be implemented in syscall-server (not in runtime):
|
I don't have permission to push into |
Replaced by #333 |
solve #239