qilingframework / qiling

A True Instrumentable Binary Emulation Framework
https://qiling.io
GNU General Public License v2.0
5.14k stars 744 forks source link

Incorrect handling of binding a socket to an already bound address (ql_syscall_bind) #1476

Closed carter-yagemann closed 4 months ago

carter-yagemann commented 4 months ago

Describe the bug

In Linux, when a target program binds a socket that is already bound, the OS should return an error code indicating that the address is already in use and the target program should proceed, but in Qiling an uncaught except is raised and execution is stopped, which is unexpected and undesired behavior.

Sample Code

Target Program Source Code: (adapted from man bind)

/* test.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#define MY_SOCK_PATH "/tmp/testsocket"
#define LISTEN_BACKLOG 50

#define handle_error(msg) \
  do { perror(msg); exit(EXIT_FAILURE); } while (0)

int
main(void)
{
    int                 sfd, cfd;
    socklen_t           peer_addr_size;
    struct sockaddr_un  my_addr, peer_addr;

    sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sfd == -1)
        handle_error("socket");

    memset(&my_addr, 0, sizeof(my_addr));
    my_addr.sun_family = AF_UNIX;
    strncpy(my_addr.sun_path, MY_SOCK_PATH,
        sizeof(my_addr.sun_path) - 1);

    printf("Bind 1\n");
    if (bind(sfd, (struct sockaddr *) &my_addr,
            sizeof(my_addr)) == -1)
        handle_error("bind");

    printf("Bind 2\n");
    if (bind(sfd, (struct sockaddr *) &my_addr,
            sizeof(my_addr)) == -1)
        handle_error("bind");

    return 0;
}

Real Execution:

gcc -o test -static test.c
./test
# output:
# Bind 1
# Bind 2
# bind: Address already in use

Qiling Emulation:

import qiling
ql = qiling.Qiling(["./root_fs/test"], "./root_fs")
ql.run()

[x] Syscall ERROR: ql_syscall_bind DEBUG: [Errno 98] Address already in use
Traceback (most recent call last):
File "/env/lib/python3.11/site-packages/qiling/os/posix/posix.py", line 374, in load_syscall
retval = syscall_hook(self.ql, *params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/env/lib/python3.11/site-packages/qiling/os/posix/syscall/socket.py", line 433, in ql_syscall_bind
sock.bind(dest)
File "/env/lib/python3.11/site-packages/qiling/os/posix/filestruct.py", line 83, in bind return self.__socket.bind(address) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ OSError: [Errno 98] Address already in use

Expected behavior Qiling should correctly handle the case where the host OS returns an "Address already in use" error and return the proper return value to the target program. Many programs use the behavior like in test.c to check for already running instances of the program.

Screenshots N/A

Additional context N/A

elicn commented 4 months ago

Hi @carter-yagemann, A fix has been committed to dev branch. I am tentatively closing the issue now. Feel free to check out the updated code and re-open this issue if the problem persists.