Sometimes I see strange usage of dup2()
function. For example:
if ((sock= accept(sockfd, (struct sockaddr *)&s_addr, &namelen)) == -1){ syslog(LOG_ERR, "in accept: %m"); exit(3); } dup2(sock, 0); close(sockfd); sock = 0;
It doesn’t even check the return value. What exactly does it do with such arguments? The man dup2
says that if newfd (second argument of dup2) was previously open, it is silently closed before being reused.
But the 0 is stdin and why do we even need to do that?
Advertisement
Answer
This is actually a fairly-common paradigm to configure a program to operate on a socket as the standard input.
By itself it probably seems pointless – why not just operate on whatever the socket descriptor is? – but in practice it’s almost always followed by a fork()
operation that runs some child process that expects to read from standard input.
Poof – now it works with the socket.
Likely you’ll see stdout manipulated in a similar way.
EDIT: A super simple example is a network service that offers you a shell after you accept a TCP connection:
... if ((sock= accept(sockfd, (struct sockaddr *)&s_addr, &namelen)) == -1){ syslog(LOG_ERR, "in accept: %m"); exit(3); } dup2(sock, 0); // stdin dup2(sock, 1); // stdout dup2(sock, 2); // stderr close(sock); system("/bin/sh"); // terrible security
So now when you connect to it – perhaps with telnet from a client – you have sort-of a shell that has what appears to be traditional stdin/out/err, all connected to the socket.
The point is you see this mainly used only when some child process has to be executed, where it assumes file descriptors 0/1/2 are set up in a certain way.
NOTE: this is a terrible idea and highly insecure, and the only time you ever see this for real is in malware. I hesitated to include the example here, but it’s such a clear illustration that I thought it worth it.