Skip to content
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

Closed
wants to merge 8 commits into from

Conversation

zhangzihengya
Copy link

@zhangzihengya zhangzihengya commented Mar 9, 2024

solve #239

@Officeyutong
Copy link
Contributor

Officeyutong commented Mar 9, 2024

/sys/bus/event_source/devices/uprobe/type was also accessed by libbpf, do you have any method to solve this?

@zhangzihengya
Copy link
Author

zhangzihengya commented Mar 9, 2024

/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");
Copy link
Contributor

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
Copy link
Contributor

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?

@Officeyutong
Copy link
Contributor

/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.

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");
Copy link
Contributor

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, ...);
Copy link
Contributor

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?

Copy link
Author

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.

Copy link
Author

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./testproduces 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.

Copy link
Contributor

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./testproduces 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?

@pull-request-size pull-request-size bot added size/L and removed size/M labels Apr 2, 2024
@Officeyutong
Copy link
Contributor

@zhangzihengya Hi, how's going on now?

@Officeyutong
Copy link
Contributor

The following logic should be implemented in syscall-server (not in runtime):

  • Hook open and openat, create a fake fd (using open for an temporary file) and return it for access to /sys/bus/event_source/devices/uprobe/type
  • Hook read, for reading request to hooked files, writting the corresponding buffer

@Officeyutong Officeyutong self-assigned this Aug 15, 2024
@Officeyutong
Copy link
Contributor

I don't have permission to push into zhangzihengya:master, so I will open a new PR

@Officeyutong
Copy link
Contributor

Replaced by #333

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants