diff options
author | alaviss <alaviss@users.noreply.github.com> | 2020-04-20 15:09:59 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-20 17:09:59 +0200 |
commit | 1bdc30bdb13422bd5eff830327582a938e7b76ac (patch) | |
tree | 48c3d5e4f677042b3dd750cae5a255768a03da1a /lib/posix | |
parent | 6bd279c97871e47c78636f3c1a8f39a7915b1402 (diff) | |
download | Nim-1bdc30bdb13422bd5eff830327582a938e7b76ac.tar.gz |
Make file descriptors from stdlib non-inheritable by default (#13201)
* io: make file descriptors non-inheritable by default This prevents file descriptors/handles leakage to child processes that might cause issues like running out of file descriptors, or potential security issues like leaking a file descriptor to a restricted file. While this breaks backward compatibility, I'm rather certain that not many programs (if any) actually make use of this implementation detail. A new API `setInheritable` is provided for the few that actually want to use this functionality. * io: disable inheritance at file creation time for supported platforms Some platforms provide extension to fopen-family of functions to allow for disabling descriptor inheritance atomically during File creation. This guards against possible leaks when a child process is spawned before we managed to disable the file descriptor inheritance (ie. in a multi-threaded program). * net, nativesockets: make sockets non inheritable by default With this commit, sockets will no longer leak to child processes when you don't want it to. Should solves a lot of "address in use" that might occur when your server has just restarted. All APIs that create sockets in these modules now expose a `inheritable` flag that allow users to toggle inheritance for the resulting sockets. An implementation of `setInheritance()` is also provided for SocketHandle. While atomically disabling inheritance at creation time is supported on Windows, it's only implemented by native winsock2, which is too much for now. This support can be implemented in a future patch. * posix: add F_DUPFD_CLOEXEC This command duplicates file descriptor with close-on-exec flag set. Defined in POSIX.1-2008. * ioselectors_kqueue: don't leak file descriptors File descriptors internally used by ioselectors on BSD/OSX are now shielded from leakage. * posix: add O_CLOEXEC This flag allows file descriptors to be open() with close-on-exec flag set atomically. This flag is specified in POSIX.1-2008 * tfdleak: test for selectors leakage Also simplified the test by using handle-type agnostic APIs to test for validity. * ioselectors_epoll: mark all fd created close-on-exec File descriptors from ioselectors should no longer leaks on Linux. * tfdleak: don't check for selector leakage on Windows The getFd proc for ioselectors_select returns a hardcoded -1 * io: add NoInheritFlag at compile time * io: add support for ioctl-based close-on-exec This allows for the flag to be set/unset in one syscall. While the performance gains might be negliable, we have one less failure point to deal with. * tfdleak: add a test for setInheritable * stdlib: add nimInheritHandles to restore old behaviors * memfiles: make file handle not inheritable by default for posix * io: setInheritable now operates on OS file handle On Windows, the native handle is the only thing that's inheritable, thus we can assume that users of this function will already have the handle available to them. This also allows users to pass down file descriptors from memfiles on Windows with ease, should that be desired. With this, nativesockets.setInheritable can be made much simpler. * changelog: clarify * nativesockets: document setInheritable return value * posix_utils: atomically disable fd inheritance for mkstemp
Diffstat (limited to 'lib/posix')
-rw-r--r-- | lib/posix/posix.nim | 7 | ||||
-rw-r--r-- | lib/posix/posix_linux_amd64_consts.nim | 3 | ||||
-rw-r--r-- | lib/posix/posix_macos_amd64.nim | 3 | ||||
-rw-r--r-- | lib/posix/posix_openbsd_amd64.nim | 2 | ||||
-rw-r--r-- | lib/posix/posix_other.nim | 3 | ||||
-rw-r--r-- | lib/posix/posix_other_consts.nim | 2 | ||||
-rw-r--r-- | lib/posix/posix_utils.nim | 6 |
7 files changed, 25 insertions, 1 deletions
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index d1f2faca5..3e423c64b 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -896,6 +896,10 @@ proc `==`*(x, y: SocketHandle): bool {.borrow.} proc accept*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen): SocketHandle {. importc, header: "<sys/socket.h>", sideEffect.} +when defined(linux) or defined(bsd): + proc accept4*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr SockLen, + flags: cint): SocketHandle {.importc, header: "<sys/socket.h>".} + proc bindSocket*(a1: SocketHandle, a2: ptr SockAddr, a3: SockLen): cint {. importc: "bind", header: "<sys/socket.h>".} ## is Posix's ``bind``, because ``bind`` is a reserved word @@ -1036,6 +1040,9 @@ proc mkstemp*(tmpl: cstring): cint {.importc, header: "<stdlib.h>", sideEffect.} proc mkdtemp*(tmpl: cstring): pointer {.importc, header: "<stdlib.h>", sideEffect.} +when defined(linux) or defined(bsd): + proc mkostemp*(tmpl: cstring, oflags: cint): cint {.importc, header: "<stdlib.h>", sideEffect.} + proc utimes*(path: cstring, times: ptr array[2, Timeval]): int {. importc: "utimes", header: "<sys/time.h>", sideEffect.} ## Sets file access and modification times. diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index 7352e8e35..84296eb9b 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -100,6 +100,7 @@ const EXDEV* = cint(18) # <fcntl.h> const F_DUPFD* = cint(0) +const F_DUPFD_CLOEXEC* = cint(1030) const F_GETFD* = cint(1) const F_SETFD* = cint(2) const F_GETFL* = cint(3) @@ -126,6 +127,7 @@ const O_ACCMODE* = cint(3) const O_RDONLY* = cint(0) const O_RDWR* = cint(2) const O_WRONLY* = cint(1) +const O_CLOEXEC* = cint(524288) const POSIX_FADV_NORMAL* = cint(0) const POSIX_FADV_SEQUENTIAL* = cint(2) const POSIX_FADV_RANDOM* = cint(1) @@ -469,6 +471,7 @@ const SOCK_DGRAM* = cint(2) const SOCK_RAW* = cint(3) const SOCK_SEQPACKET* = cint(5) const SOCK_STREAM* = cint(1) +const SOCK_CLOEXEC* = cint(524288) const SOL_SOCKET* = cint(1) const SOMAXCONN* = cint(128) const SO_REUSEPORT* = cint(15) diff --git a/lib/posix/posix_macos_amd64.nim b/lib/posix/posix_macos_amd64.nim index 536d51be5..304993dcb 100644 --- a/lib/posix/posix_macos_amd64.nim +++ b/lib/posix/posix_macos_amd64.nim @@ -557,6 +557,9 @@ when defined(linux) or defined(nimdoc): else: var SO_REUSEPORT* {.importc, header: "<sys/socket.h>".}: cint +when defined(linux) or defined(bsd): + var SOCK_CLOEXEC* {.importc, header: "<sys/socket.h>".}: cint + when defined(macosx): # We can't use the NOSIGNAL flag in the ``send`` function, it has no effect # Instead we should use SO_NOSIGPIPE in setsockopt diff --git a/lib/posix/posix_openbsd_amd64.nim b/lib/posix/posix_openbsd_amd64.nim index 408e42255..1ff636517 100644 --- a/lib/posix/posix_openbsd_amd64.nim +++ b/lib/posix/posix_openbsd_amd64.nim @@ -532,6 +532,8 @@ when defined(nimdoc): else: var SO_REUSEPORT* {.importc, header: "<sys/socket.h>".}: cint +var SOCK_CLOEXEC* {.importc, header: "<sys/socket.h>".}: cint + var MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint when hasSpawnH: diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 8213f796c..204cc3d9a 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -562,6 +562,9 @@ when defined(linux) or defined(nimdoc): else: var SO_REUSEPORT* {.importc, header: "<sys/socket.h>".}: cint +when defined(linux) or defined(bsd): + var SOCK_CLOEXEC* {.importc, header: "<sys/socket.h>".}: cint + when defined(macosx): # We can't use the NOSIGNAL flag in the ``send`` function, it has no effect # Instead we should use SO_NOSIGPIPE in setsockopt diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index 9fcbe425d..f43407b40 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -99,6 +99,7 @@ var EXDEV* {.importc: "EXDEV", header: "<errno.h>".}: cint # <fcntl.h> var F_DUPFD* {.importc: "F_DUPFD", header: "<fcntl.h>".}: cint +var F_DUPFD_CLOEXEC* {.importc: "F_DUPFD", header: "<fcntl.h>".}: cint var F_GETFD* {.importc: "F_GETFD", header: "<fcntl.h>".}: cint var F_SETFD* {.importc: "F_SETFD", header: "<fcntl.h>".}: cint var F_GETFL* {.importc: "F_GETFL", header: "<fcntl.h>".}: cint @@ -125,6 +126,7 @@ var O_ACCMODE* {.importc: "O_ACCMODE", header: "<fcntl.h>".}: cint var O_RDONLY* {.importc: "O_RDONLY", header: "<fcntl.h>".}: cint var O_RDWR* {.importc: "O_RDWR", header: "<fcntl.h>".}: cint var O_WRONLY* {.importc: "O_WRONLY", header: "<fcntl.h>".}: cint +var O_CLOEXEC* {.importc: "O_CLOEXEC", header: "<fcntl.h>".}: cint var POSIX_FADV_NORMAL* {.importc: "POSIX_FADV_NORMAL", header: "<fcntl.h>".}: cint var POSIX_FADV_SEQUENTIAL* {.importc: "POSIX_FADV_SEQUENTIAL", header: "<fcntl.h>".}: cint var POSIX_FADV_RANDOM* {.importc: "POSIX_FADV_RANDOM", header: "<fcntl.h>".}: cint diff --git a/lib/posix/posix_utils.nim b/lib/posix/posix_utils.nim index 5dbb163ca..2d0288187 100644 --- a/lib/posix/posix_utils.nim +++ b/lib/posix/posix_utils.nim @@ -83,7 +83,11 @@ proc mkstemp*(prefix: string): (string, File) = ## The file is created with perms 0600. ## Returns the filename and a file opened in r/w mode. var tmpl = cstring(prefix & "XXXXXX") - let fd = mkstemp(tmpl) + let fd = + when declared(mkostemp): + mkostemp(tmpl, O_CLOEXEC) + else: + mkstemp(tmpl) var f: File if open(f, fd, fmReadWrite): return ($tmpl, f) |