Skip to content
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

Darwin: Only set FD_CLOEXEC when creating a socket FD #14650

Closed
wants to merge 4 commits into from

Conversation

carlhoerberg
Copy link
Contributor

Not when an existing FD is passed to Socket.new

Not when a FD is passed to Socket.new
@carlhoerberg
Copy link
Contributor Author

Follow up on #14632 (review)

src/crystal/system/unix/socket.cr Outdated Show resolved Hide resolved
Co-authored-by: Johannes Müller <straightshoota@gmail.com>
@ysbaddaden
Copy link
Contributor

ysbaddaden commented Jun 3, 2024

I notice some issues with this change: when we create the socket the @handle ivar isn't set and calling #fcntl will fail (see CI) but we also set CLOEXEC for plain fd (e.g. Socket.new(fd, ...) as called from UNIXSocket.pair or Socket#accept? for example.

@straight-shoota
Copy link
Member

when we create the socket the @handle ivar isn't set and calling #fcntl will fail (see CI)

Yeah I think we need to use LibC.fcntl(fd, ...) like before to fix the current failure. The file descriptor is not assigned yet, so we cannot use #fcntl.

we also set CLOEXEC for plain fd (e.g. Socket.new(fd, ...) as called from UNIXSocket.pair or Socket#accept? for example.

Yes, that's the current behaviour. But I believe it's wrong. We probably shouldn't autoclose a file descriptor that's coming from outside the process. Only close what we opened ourselves.
That means all uses in stdlib like Socket#accept? need to be updated to explicitly set close on exec.

However, I'm wondering if this isn't too bad a silent breaking change in behaviour... 🤔

@ysbaddaden
Copy link
Contributor

ysbaddaden commented Jun 3, 2024

I agree: it may not be the best API, but security-wise it doesn't sound like a bad practice to always close file descriptors on exec... and maybe always calling fcntl ain't a bad idea instead of setting O_CLOEXEC after all? If you need it to not be closed on exec, you can always call fcntl to disable the flag.

Co-authored-by: Sijawusz Pur Rahnama <sija@sija.pl>
Copy link
Contributor

@ysbaddaden ysbaddaden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following methods (at least) must also be fixed to set FD_CLOEXEC for darwin targets:

  • Socket#accept?
  • UNIXSocket#accept?
  • UNIXSocket.pair

Maybe there should be a system method to set FD_CLOEXEC on a given fd to avoid repeating the same LibC.fcntl call? Something like Crystal::System::FileDescriptor.set_close_on_exec(fd : Int32) : Nil.

Why Apple wouldn't implement the O_CLOEXEC SOCK_CLOEXEC flag is beyond me 😮‍💨

@straight-shoota
Copy link
Member

straight-shoota commented Jun 4, 2024

Yeah, I suppose we should also setup specs for those methods.

@carlhoerberg If you want to go on, please continue. But we'll be happy to take over these final steps if you prefer. Just say the word.

@carlhoerberg
Copy link
Contributor Author

Go for it! :)

ysbaddaden added a commit that referenced this pull request Jun 14, 2024
Harmonizes the implementations between Darwin and other POSIX platforms
for the "close on exec" behavior.

When `SOCK_CLOEXEC` is available, we always use it in the `socket`,
`socketpair` and `accept4` syscalls. When `SOCK_CLOEXEC` isn't
available, we don't delay to `Socket#initialize_handle` anymore to set
`FD_CLOEXEC` for Darwin only, but immediately call `fcntl` to set it
after the above syscalls.

The `accept4` syscall is non-standard but widely available: Linux, all
supported BSD, except for Darwin (obviously).

The patch also fixes an issue where TCP and UNIX client sockets didn't
have `FD_CLOEXEC` on POSIX platforms... except for Darwin.

closes #14650
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants