Unix library: better API for "close-on-exec" over file descriptors#650
Unix library: better API for "close-on-exec" over file descriptors#650damiendoligez merged 16 commits intotrunkfrom
Conversation
|
Very happy to see this being worked on again. The proposed solution and PR look fine to me! I was wondering: would it be interesting to add a global switch or maybe a module functor that would allow the programmer to have a |
|
@toots: yes, it makes a lot of sense to have programmer's control on the default value. (For example, the SecureOCaml people should probably have "close on exec" as the default.) We did something like that for hashtable randomization in OCaml 4.00. Maybe a similar API could be used here. |
otherlibs/unix/dup.c
Outdated
| int ret; | ||
| #ifdef F_DUPFD_CLOEXEC | ||
| if (unix_cloexec_p(cloexec)) | ||
| ret = fcntl(F_DUPFD_CLOEXEC, Int_val(fd)); |
There was a problem hiding this comment.
I think the arguments to this fcntl call are the wrong way round.
There was a problem hiding this comment.
Well spotted, thanks! Pushing a fix...
|
I am in favour. I spotted one bug, but can have a closer look once it's been tested. |
|
I saw a recent proposal to reorganize the stdlib into a new "namespace" Std, including putting the channel functions into Std.IO. Wouldn't that also be a good way to make close_on_exec the default? As in all the functions in Std.IO will default to close_on_exec while the old functions use keep_on_exec. |
|
I fixed the Win32 implementation and added some tests. This PR is ready for review. Concerning the API, the implementation now makes it trivial to change the default for close-on-exec. I haven't added an API function to do this yet. |
otherlibs/win32unix/unix.ml
Outdated
| let fd3 = dup ~cloexec:false fd3 in | ||
| let res = win_create_process prog args optenv fd1 fd2 fd3 in | ||
| close fd1; close fd2; close fd3; | ||
| res |
There was a problem hiding this comment.
Doesn't a race condition can make the new fd1,fd2,fd3 go into another sub-process, since contrary to the unix version we are not inside a fork?
There was a problem hiding this comment.
If dup, win_create_process or close releases the runtime lock or invokes the GC then another thread could run before the final close. If that thread then also calls create_process_aux the duplicated FDs will leak.
I'm assuming dup and close will be save here but win_create_process probably allocates something. So I agree with @bobot about the race condition. I think the dup should be moved into the win_create_process C stub and run with the runtime lock held. This would still race with non-ocaml threads forking at the same time but it's the best you can do.
There was a problem hiding this comment.
I'm assuming dup
I don't think so. Under Windows, handles are wrapped into head-allocated custom blocks, so dup can easily trigger the GC.
There was a problem hiding this comment.
@xavierleroy What about fd leaks when win_create_process (or dup) raises an exception?
|
@alainfrisch : Here is an explanation of the change in create_process for Win32. I think it makes it work in cases where the previous implementation would misbehave, and I don't think it can break. Assume you call Unix.create_process with redirections to three new file descriptors fd1, fd2, fd3. Further assume that fd1, fd2, fd3 are close-on-exec, like they should be so that they won't be inherited by the new process.
The reason why I don't think this change can break code that works today is that, in order for that code to work in Win32, the fds passed to create_process must be keep-on-exec. In this case, the new implementation behaves pretty much like the old one. |
|
I propose to add to the creating process functions a way to specify which fd must be passed to the created process. Perhaps with the destination file descriptor, in the same way that However it seems that there is never enough provided after fork actions (resource limitation, user change, namespace) so perhaps it should go in external library (even Core/Async_extended |
|
@bobot : yes, we (still) have a race condition. At this point I don't see how to avoid it based on the CreateProcess Win32 API, but I'll keep searching on StackOverflow... |
|
More info on CreateProcess, redirections and handle inheritance: https://blogs.msdn.microsoft.com/oldnewthing/20111216-00/?p=8873. It looks like there is a drastic solution where no handle is ever inherited, except those that become the new standard handles of the created process. This is very secure indeed but would cause problems with hypothetical applications that pass extra inherited handles through side channels (handle number as command-line parameter, for example). |
|
@mrvn @alainfrisch : yes, the current Win32 implementation is a proof-of-concept and I'll improve it along the lines you suggest. But a race condition will remain with concurrent CreateProcess calls made directly from C. Is this good enough or should we look into the more drastic solution mentioned in my previous comment? |
|
I'm not sure that the risk of breaking existing code with the more drastic solution is so high, esp. since our Unix module does not expose handle directly. To be on the safe side, this could always be controlled by a global switch, although this becomes more and more ugly. Ideally, there would be a way to emulate the strict mode on Unix and add an optional parameter to process-creation function to control it. But my understanding is that this is precisely what is difficult to achieve on Unix, right? |
|
I don't think this can ever be fully race free unless there is kernel support for actually atomically passing a specific set of FDs to the new process. Oh wait, there is since Vista. @xavierleroy I would totaly go with the solution from the page you mentioned with an insecure fallback if the syscall isn't present. It was made for exactly this case after all. |
|
I know it's my time to move. Will try to improve createprocess, at least by moving the dup dance into the C code, so that it is more atomic and errors are handled better, and will move that we merge then. |
|
The new Jane Street "shexp" package has a carefully-written implementation for spawning Unix processes that may (or may not) be of use for reference too. I think there may be a newer version available than the current version on Jane Street's github (please ask @diml if this is of interest). |
This is one possible answer to the long-standing problem described in MPR#5256: http://caml.inria.fr/mantis/view.php?id=5256 All Unix functions that create file descriptors now have a way to specify if the descriptor is to be close-on-exec or keep-on-exec: - either via an optional argument ~cloexec:bool - or, in the case of Unix.openfile, via flags O_CLOEXEC and O_KEEPEXEC. For backward compatibility, keep-on-exec is the default, but the implementation makes it trivially easy to switch to close-on-exec by default in the future. To avoid race conditions (that can occur when a descriptor is created in keep-on-exec mode then switched to close-on-exec), the implementation uses the new system calls pipe2(), dup3() and accept4() when they are available. So far these syscalls are Linux-specific, but there is hope that similar functionality will be standardized one day (see http://www.austingroupbugs.net/view.php?id=411). The win32unix implementation hasn't been updated yet.
Tentative implementation: not tested, not even compiled.
Also: refactor the code between the cloexec/keepexec cases.
This is a first step towards making the default controllable by the user. Also: in Unix.openfile, make sure that if O_CLOEXEC and O_KEEPEXEC are given, O_CLOEXEC wins.
win32unix/open.c: wrong interpretation of default close-on-exec win32unix/unix.ml: duplicate handles in create_process, for consistency with the unix implementation tests/lib-unix: problems with deleting a file while it is open
The "dup" operations are done in C for better atomicity. FDs are properly closed in case of error.
otherlibs/win32unix/unix.ml
Outdated
| close out_read; close in_write; close err_write; | ||
| begin | ||
| try | ||
| open_proc cmd (Some env) (Process_full(inchan, outchan, errchan)) |
There was a problem hiding this comment.
I think this should be (Some(make_process_env env))
Note: the test lib-unix/redirections.ml sometimes fails (mingw32 port). To be investigated.
Closing the standard input causes errors in open_process_out because the Win32 CreateProcess syscall demands that all standard handles are valid. Strangely, the error is semi-random and occurs about once every 3 runs.
In the Lwt_unix module, add `?cloexec:bool` optional arguments to functions that create file descriptors (`dup`, `dup2`, `pipe`, `pipe_in`, `pipe_out`, `socket`, `socketpair`, `accept`, `accept_n`). The `?cloexec` argument is simply forwarded to the wrapped Unix function (with OCaml >= 4.05, see [ocaml/ocaml#650][650]), or emulated as best-effort with `Unix.set_close_on_exec` on older OCaml versions. Fix ocsigen#327. Fix ocsigen#847. See also ocsigen#872. [650]: ocaml/ocaml#650
In the Lwt_unix module, add `?cloexec:bool` optional arguments to functions that create file descriptors (`dup`, `dup2`, `pipe`, `pipe_in`, `pipe_out`, `socket`, `socketpair`, `accept`, `accept_n`). The `?cloexec` argument is simply forwarded to the wrapped Unix function (with OCaml >= 4.05, see [ocaml/ocaml#650][650]), or emulated as best-effort with `Unix.set_close_on_exec` on older OCaml versions. Fix ocsigen#327. Fix ocsigen#847. See also ocsigen#872. [650]: ocaml/ocaml#650
The current code makes the assumption that handles are not inheritable (close-on-exec), and duplicates handles to mark them inheritable (keep-on-exec) for the child process. That assumption is only mentioned in ocaml#650, and not documented in the manual. It's possible however that the calling code gives to create_process handles that are already inheritable: either because the programmer isn't aware of the security implications, or because the programmer expects create_process to be a "simple" wrapper around WinAPI's CreateProcess; in which case setting the handle inheritable would be the responsibility of the calling code. Converting the canonical example from Microsoft documentation [1] without looking at win32unix's create_process would lead to this problem. In either case, the current create_process would needlessly duplicate an already inheritable handle and leak the original handle in the child process. We can instead check whether the given handles are inheritable, and only duplicate them if they're not. The calling code is still responsible for closing the original handle. [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
Unix.create_process duplicates the handles given to the child process if they're not inheritable. Mimic this behaviour in Lwt for consistency. See the following PRs: - [Unix library: better API for "close-on-exec" over file descriptors ocsigen#650](ocaml/ocaml#650); - [win32unix create_process: duplicate std handles in create_process iff they're not inheritable #10807](ocaml/ocaml#650).
The current code makes the assumption that handles are not inheritable (close-on-exec), and duplicates handles to mark them inheritable (keep-on-exec) for the child process. That assumption is only mentioned in ocaml#650, and not documented in the manual. It's possible however that the calling code gives to create_process handles that are already inheritable: either because the programmer isn't aware of the security implications, or because the programmer expects create_process to be a "simple" wrapper around WinAPI's CreateProcess; in which case setting the handle inheritable would be the responsibility of the calling code. Converting the canonical example from Microsoft documentation [1] without looking at win32unix's create_process would lead to this problem. In either case, the current create_process would needlessly duplicate an already inheritable handle and the child process would inherit both the original and the duplicated handles. We can instead check whether the given handles are inheritable, and only duplicate them if they're not. The calling code is still responsible for closing the original handle. [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
…s_for_effect_functions Add primitives necessary for exposing effect handlers as functions
The current code makes the assumption that handles are not inheritable (close-on-exec), and duplicates handles to mark them inheritable (keep-on-exec) for the child process. That assumption is only mentioned in ocaml#650, and not documented in the manual. It's possible however that the calling code gives to create_process handles that are already inheritable: either because the programmer isn't aware of the security implications, or because the programmer expects create_process to be a "simple" wrapper around WinAPI's CreateProcess; in which case setting the handle inheritable would be the responsibility of the calling code. Converting the canonical example from Microsoft documentation [1] without looking at win32unix's create_process would lead to this problem. In either case, the current create_process would needlessly duplicate an already inheritable handle and the child process would inherit both the original and the duplicated handles. We can instead check whether the given handles are inheritable, and only duplicate them if they're not. The calling code is still responsible for closing the original handle. [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
Unix.create_process duplicates the handles given to the child process if they're not inheritable. Mimic this behaviour in Lwt for consistency. See the following PRs: - [Unix library: better API for "close-on-exec" over file descriptors ocsigen#650](ocaml/ocaml#650); - [win32unix create_process: duplicate std handles in create_process iff they're not inheritable #10807](ocaml/ocaml#650).
The current code makes the assumption that handles are not inheritable (close-on-exec), and duplicates handles to mark them inheritable (keep-on-exec) for the child process. That assumption is only mentioned in ocaml#650, and not documented in the manual. It's possible however that the calling code gives to create_process handles that are already inheritable: either because the programmer isn't aware of the security implications, or because the programmer expects create_process to be a "simple" wrapper around WinAPI's CreateProcess; in which case setting the handle inheritable would be the responsibility of the calling code. Converting the canonical example from Microsoft documentation [1] without looking at win32unix's create_process would lead to this problem. In either case, the current create_process would needlessly duplicate an already inheritable handle and the child process would inherit both the original and the duplicated handles. We can instead check whether the given handles are inheritable, and only duplicate them if they're not. The calling code is still responsible for closing the original handle. [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
Unix.create_process duplicates the handles given to the child process if they're not inheritable. Mimic this behaviour in Lwt for consistency. See the following PRs: - [Unix library: better API for "close-on-exec" over file descriptors ocsigen#650](ocaml/ocaml#650); - [win32unix create_process: duplicate std handles in create_process iff they're not inheritable #10807](ocaml/ocaml#650).
The current code makes the assumption that handles are not inheritable (close-on-exec), and duplicates handles to mark them inheritable (keep-on-exec) for the child process. That assumption is only mentioned in ocaml#650, and not documented in the manual. It's possible however that the calling code gives to create_process handles that are already inheritable: either because the programmer isn't aware of the security implications, or because the programmer expects create_process to be a "simple" wrapper around WinAPI's CreateProcess; in which case setting the handle inheritable would be the responsibility of the calling code. Converting the canonical example from Microsoft documentation [1] without looking at win32unix's create_process would lead to this problem. In either case, the current create_process would needlessly duplicate an already inheritable handle and the child process would inherit both the original and the duplicated handles. Consider the following pipeline: `writer | child | reader`. The problem with the child process having duplicated "leaked" stdin and stdout handles is that while it is running, it cannot signal to the writer that it should stop writing: the writer will not see a broken pipe as the child still has the leaked duplicated handle open. The same thing happens to the reader with the stdout of the child. Usually stdin/stdout are bound to the lifetime of the process, so this is not too much of a problem, but if the child itself spawns processes that should outlive it, the whole thing can become messy. We can instead check whether the given handles are inheritable, and only duplicate them if they're not. The calling code is still responsible for closing the original handle. [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
The current code makes the assumption that handles are not inheritable (close-on-exec), and duplicates handles to mark them inheritable (keep-on-exec) for the child process. That assumption is only mentioned in ocaml#650, and not documented in the manual. It's possible however that the calling code gives to create_process handles that are already inheritable: either because the programmer isn't aware of the security implications, or because the programmer expects create_process to be a "simple" wrapper around WinAPI's CreateProcess; in which case setting the handle inheritable would be the responsibility of the calling code. Converting the canonical example from Microsoft documentation [1] without looking at win32unix's create_process would lead to this problem. In either case, the current create_process would needlessly duplicate an already inheritable handle and the child process would inherit both the original and the duplicated handles. Consider the following pipeline: `writer | child | reader`. The problem with the child process having duplicated "leaked" stdin and stdout handles is that while it is running, it cannot signal to the writer that it should stop writing: the writer will not see a broken pipe as the child still has the leaked duplicated handle open. The same thing happens to the reader with the stdout of the child. Usually stdin/stdout are bound to the lifetime of the process, so this is not too much of a problem, but if the child itself spawns processes that should outlive it, the whole thing can become messy. We can instead check whether the given handles are inheritable, and only duplicate them if they're not. The calling code is still responsible for closing the original handle. [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
Unix.create_process duplicates the handles given to the child process if they're not inheritable. Mimic this behaviour in Lwt for consistency. See the following PRs: - [Unix library: better API for "close-on-exec" over file descriptors ocsigen#650](ocaml/ocaml#650); - [win32unix create_process: duplicate std handles in create_process iff they're not inheritable #10807](ocaml/ocaml#650).
Unix.create_process duplicates the handles given to the child process if they're not inheritable. Mimic this behaviour in Lwt for consistency. See the following PRs: - [Unix library: better API for "close-on-exec" over file descriptors ocsigen#650](ocaml/ocaml#650); - [win32unix create_process: duplicate std handles in create_process iff they're not inheritable #10807](ocaml/ocaml#650).
Unix.create_process duplicates the handles given to the child process if they're not inheritable. Mimic this behaviour in Lwt for consistency. See the following PRs: - [Unix library: better API for "close-on-exec" over file descriptors ocsigen#650](ocaml/ocaml#650); - [win32unix create_process: duplicate std handles in create_process iff they're not inheritable #10807](ocaml/ocaml#650).
The current code makes the assumption that handles are not inheritable (close-on-exec), and duplicates handles to mark them inheritable (keep-on-exec) for the child process. That assumption is only mentioned in ocaml#650, and not documented in the manual. It's possible however that the calling code gives to create_process handles that are already inheritable: either because the programmer isn't aware of the security implications, or because the programmer expects create_process to be a "simple" wrapper around WinAPI's CreateProcess; in which case setting the handle inheritable would be the responsibility of the calling code. Converting the canonical example from Microsoft documentation [1] without looking at win32unix's create_process would lead to this problem. In either case, the current create_process would needlessly duplicate an already inheritable handle and the child process would inherit both the original and the duplicated handles. Consider the following pipeline: `writer | child | reader`. The problem with the child process having duplicated "leaked" stdin and stdout handles is that while it is running, it cannot signal to the writer that it should stop writing: the writer will not see a broken pipe as the child still has the leaked duplicated handle open. The same thing happens to the reader with the stdout of the child. Usually stdin/stdout are bound to the lifetime of the process, so this is not too much of a problem, but if the child itself spawns processes that should outlive it, the whole thing can become messy. We can instead check whether the given handles are inheritable, and only duplicate them if they're not. The calling code is still responsible for closing the original handle. [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
The current code makes the assumption that handles are not inheritable (close-on-exec), and duplicates handles to mark them inheritable (keep-on-exec) for the child process. That assumption is only mentioned in ocaml#650, and not documented in the manual. It's possible however that the calling code gives to create_process handles that are already inheritable: either because the programmer isn't aware of the security implications, or because the programmer expects create_process to be a "simple" wrapper around WinAPI's CreateProcess; in which case setting the handle inheritable would be the responsibility of the calling code. Converting the canonical example from Microsoft documentation [1] without looking at win32unix's create_process would lead to this problem. In either case, the current create_process would needlessly duplicate an already inheritable handle and the child process would inherit both the original and the duplicated handles. Consider the following pipeline: `writer | child | reader`. The problem with the child process having duplicated "leaked" stdin and stdout handles is that while it is running, it cannot signal to the writer that it should stop writing: the writer will not see a broken pipe as the child still has the leaked duplicated handle open. The same thing happens to the reader with the stdout of the child. Usually stdin/stdout are bound to the lifetime of the process, so this is not too much of a problem, but if the child itself spawns processes that should outlive it, the whole thing can become messy. We can instead check whether the given handles are inheritable, and only duplicate them if they're not. The calling code is still responsible for closing the original handle. [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
Unix.create_process duplicates the handles given to the child process if they're not inheritable. Mimic this behaviour in Lwt for consistency. See the following PRs: - [Unix library: better API for "close-on-exec" over file descriptors ocsigen#650](ocaml/ocaml#650); - [win32unix create_process: duplicate std handles in create_process iff they're not inheritable #10807](ocaml/ocaml#650).
The current code makes the assumption that handles are not inheritable (close-on-exec), and duplicates handles to mark them inheritable (keep-on-exec) for the child process. That assumption is only mentioned in ocaml#650, and not documented in the manual. It's possible however that the calling code gives to create_process handles that are already inheritable: either because the programmer isn't aware of the security implications, or because the programmer expects create_process to be a "simple" wrapper around WinAPI's CreateProcess; in which case setting the handle inheritable would be the responsibility of the calling code. Converting the canonical example from Microsoft documentation [1] without looking at win32unix's create_process would lead to this problem. In either case, the current create_process would needlessly duplicate an already inheritable handle and the child process would inherit both the original and the duplicated handles. Consider the following pipeline: `writer | child | reader`. The problem with the child process having duplicated "leaked" stdin and stdout handles is that while it is running, it cannot signal to the writer that it should stop writing: the writer will not see a broken pipe as the child still has the leaked duplicated handle open. The same thing happens to the reader with the stdout of the child. Usually stdin/stdout are bound to the lifetime of the process, so this is not too much of a problem, but if the child itself spawns processes that should outlive it, the whole thing can become messy. We can instead check whether the given handles are inheritable, and only duplicate them if they're not. The calling code is still responsible for closing the original handle. [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
… iff they're not inheritable (#10807) * win32unix: test if create_process leaks std handles * win32unix: duplicate handle in create_process iff not inheritable The current code makes the assumption that handles are not inheritable (close-on-exec), and duplicates handles to mark them inheritable (keep-on-exec) for the child process. That assumption is only mentioned in #650, and not documented in the manual. It's possible however that the calling code gives to create_process handles that are already inheritable: either because the programmer isn't aware of the security implications, or because the programmer expects create_process to be a "simple" wrapper around WinAPI's CreateProcess; in which case setting the handle inheritable would be the responsibility of the calling code. Converting the canonical example from Microsoft documentation [1] without looking at win32unix's create_process would lead to this problem. In either case, the current create_process would needlessly duplicate an already inheritable handle and the child process would inherit both the original and the duplicated handles. Consider the following pipeline: `writer | child | reader`. The problem with the child process having duplicated "leaked" stdin and stdout handles is that while it is running, it cannot signal to the writer that it should stop writing: the writer will not see a broken pipe as the child still has the leaked duplicated handle open. The same thing happens to the reader with the stdout of the child. Usually stdin/stdout are bound to the lifetime of the process, so this is not too much of a problem, but if the child itself spawns processes that should outlive it, the whole thing can become messy. We can instead check whether the given handles are inheritable, and only duplicate them if they're not. The calling code is still responsible for closing the original handle. [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
Unix.create_process duplicates the handles given to the child process if they're not inheritable. Mimic this behaviour in Lwt for consistency. See the following PRs: - [Unix library: better API for "close-on-exec" over file descriptors ocsigen#650](ocaml/ocaml#650); - [win32unix create_process: duplicate std handles in create_process iff they're not inheritable #10807](ocaml/ocaml#650).
Unix.create_process duplicates the handles given to the child process if they're not inheritable. Mimic this behaviour in Lwt for consistency. See the following PRs: - [Unix library: better API for "close-on-exec" over file descriptors ocsigen#650](ocaml/ocaml#650); - [win32unix create_process: duplicate std handles in create_process iff they're not inheritable #10807](ocaml/ocaml#650).
The `git clean -dfx` command suggested in `HACKING.md` deletes any file that's untracked but not ignored, which is unnecessary and possibly a nasty surprise. `git clean -dfX` instead *only* deletes ignored files.
This is one possible answer to the long-standing problem described in MPR#5256.
Background
An historical accident of the Unix API is that, by default, all file descriptors remain open when a program is started via
exec: the new program inherits those file descriptors. This is often a security issue, making it possible for the new program to access files and sockets it could not have otherwise, just because the original program forgot to close the corresponding file descriptors beforeexec.To mitigate this problem, a file descriptor can be marked "close on exec" (e.g. with
Unix.set_close_on_exec). Then, the kernel will automatically close it during theexeccall, and it will not leak to the new program.However, in multithreaded programs, a race condition exists: if a concurrently-executing thread does
forkandexecafter the file descriptor is created but beforeset_close_on_execis applied to it, the descriptor still leaks. To address this issue, theopensystem call has aO_CLOEXECflag that atomically sets "close on exec" on the file descriptor as it is created. Linux adds variants of other system calls (pipe2,dup3,accept4) that do the same for other cases of file descriptor creation. So far these syscalls are Linux-specific, but there is hope that similar functionality will be standardized one day (see http://www.austingroupbugs.net/view.php?id=411).Proposed solution
Several approaches to the problem above were discussed in MPR#5256. This pull request implements a solution that still relies on programmer's discipline but should not introduce major incompatibilities:
~cloexec:boolUnix.openfile, via flagsO_CLOEXECandO_KEEPEXEC.Plans for the future
At some future point, it would make a lot of sense to switch the default behavior to "close-on-exec" instead of "keep-on-exec", as it is more secure. Other languages have already made that switch, e.g. Python and Ruby. If we do this now in OCaml it would break too much code. However, with the new API proposed in this pull request, programmers can start religiously annotating their Unix system calls with the appropriate
~cloexecargument. If they do this consistently on all the code that relies on file descriptor inheritance acrossexec, we will then be able to switch the default to "close-on-exec" and their code will keep working.Current status
The implementation is at the prototype stage and needs more testing. (The Windows implementation wasn't even compiled, let alone tested.) I'm putting it as a pull request early so as to have a discussion on the API and on whether it's a good solution to the problem.