11

Basically, I need to know what is the purpose of setting the SOCK_CLOEXEC when sitting it with accept4(). how can I check the functionality of this flag with the returned file descriptor from the accept.

accepted_fd =   accept4(sd, (struct sockaddr *)& tcp_remote, &size,  SOCK_CLOEXEC);
Hatem Mashaqi
  • 610
  • 1
  • 7
  • 18

1 Answers1

14

The reason for SOCK_CLOEXEC to exist is to avoid a race condition between getting a new socket from accept and setting the FD_CLOEXEC flag afterwards.

Normally if you want the file descriptor to be close-on-exec you'd first obtain the file descriptor in some way, then call fcntl(fd, F_SETFD, FD_CLOEXEC). But in a threaded program there is a possibility for a race condition between getting that file descriptor (in this case from accept) and setting the CLOEXEC flag. Therefore Linux has recently changed most (if not all) system calls that return new file descriptors to also accept flags that tell the kernel to atomically set the close-on-exec flag before making the file descriptor valid. That way the race condition is closed.

If you wonder why close on exec exists, it's because in some cases, especially when you're executing non-privileged programs from a privileged one, you don't want some file descriptors to leak to that program.

Art
  • 19,807
  • 1
  • 34
  • 60
  • 4
    I wouldn't describe `O_CLOEXEC` as there principally for privilege escalation / security reasons -- it's also very, very common to have non-security bugs happen (frequently of the indefinite-blocking variety) if a FD is left open beyond when it's intended to be closed because a subprocess still has it. – Charles Duffy Mar 10 '14 at 16:07
  • 2
    ...it's unhelpful to encourage folks to think "oh, that's not something I need to worry about" if they aren't dealing with processes with different privilege levels. – Charles Duffy Mar 10 '14 at 16:08
  • The discussion that led to the decision for implementing all those changed and added system calls was entirely centered around security reasons. A file descriptor being left open by multiple processes is unrelated to close-on-exec since close on exec isn't close on fork. It's a different domain of problems. And actually, other than "last close actually closes" semantics of character devices, I'm not aware of many non-security issues caused by leaving file descriptors open. – Art Mar 10 '14 at 16:13
  • I've hit plenty of such issues personally -- mostly on proprietary codebases, or I'd be pointing you to bug reports and patches. Think about the normal process of spawning a subprocess connected by a pair of pipes, writing to it, closing the outbound pipe, reading from the inbound pipe, and wait()ing for it when done. If you spawned a subprocess before the outbound pipe was closed, and that subprocess holds the FD open indefinitely, you can get into a situation where that process will never finish its read, and thus never exit. – Charles Duffy Mar 10 '14 at 16:18
  • ...yes, it's last-close-actually-closes that's the problem, but, well, that's a big one. :) – Charles Duffy Mar 10 '14 at 16:54
  • Thank you guys for your answers, but please can you please provide me by a way to test an FD that had set the SOCK_CLOEXEC, I could test the functionality of FD (returned by accept4 ) when sets SOCK_NOBLOCK .. but I need to see how SOCK_CLOEXEC works .. because I haven;t dealt with this before, I tried fork but it doesn't work ! I don't know how to check that with exec() or any basic functionality – Hatem Mashaqi Mar 11 '14 at 09:05
  • You can check the flag by calling `fcntl` with `F_GETFD`. Read the man page for details. – Art Mar 11 '14 at 18:35