-
Notifications
You must be signed in to change notification settings - Fork 431
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
When 32-bit applications run on x86-64 machines, the tracee loses tracking of syscalls like socket and connect. #3676
Comments
@lclin56, I've only tested on the host so far, but I noticed that the connect call wasn't being detected because it wasn't finished (wrong address without timeout) - you can press
So I changed your PoC to reflect that. Please do more tests using it and let us know the results. int main() {
int sockfd;
struct sockaddr_in server_addr;
struct timeval timeout;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("Could not create socket");
return 1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(23);
if (inet_pton(AF_INET, "0.0.0.0", &server_addr.sin_addr) <= 0) {
perror("Invalid address/ Address not supported");
close(sockfd);
return 1;
}
// Set timeout
timeout.tv_sec = 3; // 3 seconds
timeout.tv_usec = 0; // 0 microseconds
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof timeout) < 0) {
perror("setsockopt failed");
close(sockfd);
return 1;
}
printf("About to call connect()...\n");
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection Failed");
close(sockfd);
return 1;
}
printf("Connected to the server successfully.\n");
// ...
close(sockfd);
return 0;
} |
I'm sorry, I missed an important detail. The compilation command I used for the PoC is
Based on the current results, it seems that there might be some issues with tracee when tracing 32-bit programs running on an x86-64 machine. |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as off-topic.
This comment was marked as off-topic.
Ok, I would start with:
and pick the execution path from both, the env where it worked and where it did not. Check if there are any changes in execution path. Then I would place a printk in the hooks for the event before any other logic and check if the hook is even being executed. Finally, it could be that the 32bit syscall emulation doesn't include the security_socket event, but the regular syscall execution path does (at least in the older kernels). If newer kernels have those, you are able to track the change and discover why it works in newer ones. |
Not working environment
|
Well, __ia32_compat_sys_socketcall and __ia32_sys_socket is what you are probably looking for then (I was =D). One is the old syscall entry (multiplexed), used in 32-bit environments, and the other is the new syscall handler (one handler per functionality: socket, bind, connect, listen, accept, ...). This explains why the cmdline: sudo ./tracee-ebpf -s comm=conntest -e syscalls --capabilities bypass=true does not give you a "socket" event. Because that event not exist, instead the socketcall event should appear. (1) We should check if we're able to trace socketcall() events when running binaries in compatibility mode. Also, In the eBPF code we have: SO we could be returning there. (2) needs to check if security_socket_create event is generated when socketcall(SYS_SOCKET) is called. |
Okay so with: sudo ./dist/tracee --install-path /tmp/tracee --cache cache-type=mem --cache mem-cache-size=512 --output option:sort-events --output json --output option:parse-arguments --events security_socket_create Im able to pick the the security_socket_connect event A SINGLE TIME: when originated by a "socketcall" entry and it was likely a bug in the logic (as you can see there is no socket fd, no sockaddr values, within the event). All other times I was not able to generate a security_socket_event when executing the example code. Very likely because of the logic that checks if the syscall that is generating the security event was "connect" (and in our case it is not). There is also the fact that we have to check, if socketcall(CONNECT) is the entry point to the kernel, we have to pick in security_socket_create hook in a different way (and then generate the event with the correct arguments). Because of (likely) some race condition, the event worked when it should have not. My proposal to you @geyslan: (1) You have to check the "current syscall id" inside security_socket_connect(). Then, if its connect the current logic is correct. If the entry syscall was int connect(int socket, const struct sockaddr *address, socklen_t address_len);
int syscall(SYS_socketcall, int call, unsigned long *args); I believe the initial 2 args should be skipped, sockfd would come from the 3rd argument, etc. Then you have to emit security_socket_event if the entry point was (2) Unfortunately thats not all. We have now to do the same thing for all "network security events". All the possible Ping me if you have any doubt. Cheers! |
I've been checking this a bit more today by running tracee like:
And by having With that I was expecting to catch the
id after (value) should be 473: So, this 0dbc8e4 enables getting
@rafaeldtinoco what you proposed will be tackled next. 👍🏼 |
I had always a constant thinking that the id32s could be broken (no specific testing, etc). Nice catch. |
Depending on the kernel version, 32-bit binaries use either the socketcall syscall as a entry point for socket syscalls functions, or the individual syscalls (socket, bind, connect, etc). Context: aquasecurity#3676
Depending on the kernel version, 32-bit binaries use either the socketcall syscall as a entry point for socket syscalls functions, or the individual syscalls (socket, bind, connect, etc). Context: aquasecurity#3676
The Linux kernel version determines x86 32-bit compatibility: older versions use 'socketcall' syscall for socket functions (like socket, bind, connect), while newer versions use individual syscalls directly. Context: aquasecurity#3676
The Linux kernel version determines x86 32-bit compatibility: older versions use 'socketcall' syscall for socket functions (like socket, bind, connect), while newer versions use individual syscalls directly. Context: aquasecurity#3676
The Linux kernel version determines x86 32-bit compatibility: older versions use 'socketcall' syscall for socket functions (like socket, bind, connect), while newer versions use individual syscalls directly. These changes were also tested on an arm64 running an armhf binary. Context: aquasecurity#3676
The Linux kernel version determines x86 32-bit compatibility: older versions use 'socketcall' syscall for socket functions (like socket, bind, connect), while newer versions use individual syscalls directly. These changes were also tested on an arm64 running an armhf binary. Context: #3676
Description
I hope to trace the syscall calls of a new process within a container. When I tested with this program, I encountered a problem: if the connect connection fails, I won't be able to see the records of calls such as socket and connect printed by tracee-ebpf.
This is the C language code for my test program:
This is the command line I use to run tracee:
This is the output of tracee-ebpf:
Output of
tracee version
:Output of
uname -a
:Additional details
I expect to see the "socket" call that creates the socketfd and the "connect" call that establishes the connection in the output of tracee-ebpf, even if the connect fails. However, it seems that the records of these two calls are not visible in the output.
The text was updated successfully, but these errors were encountered: