@@ -25,6 +25,9 @@ import Control.Concurrent.Class.MonadMVar (MonadMVar)
2525import Control.Concurrent.Class.MonadSTM.Strict
2626import Control.DeepSeq (NFData )
2727import Control.Exception (IOException )
28+ #if !defined(mingw32_HOST_OS) && !defined(wasm32_HOST_ARCH)
29+ import Control.Monad (when )
30+ #endif
2831import Control.Monad.Class.MonadAsync (Async , MonadAsync )
2932import Control.Monad.Class.MonadAsync qualified as Async
3033import Control.Monad.Class.MonadFork
@@ -33,6 +36,10 @@ import Control.Monad.Class.MonadTime.SI
3336import Control.Monad.Class.MonadTimer.SI
3437import Control.Monad.Fix (MonadFix )
3538import Control.Tracer (Tracer , contramap , nullTracer , traceWith )
39+ #if !defined(mingw32_HOST_OS) && !defined(wasm32_HOST_ARCH)
40+ import Data.Bits ((.|.) )
41+ import System.Posix.Files qualified as Unix
42+ #endif
3643import Data.ByteString.Lazy (ByteString )
3744import Data.Hashable (Hashable )
3845import Data.IP qualified as IP
@@ -77,7 +84,8 @@ import Ouroboros.Network.PeerSharing (PeerSharingRegistry (..))
7784import Ouroboros.Network.Protocol.Handshake
7885import Ouroboros.Network.RethrowPolicy
7986import Ouroboros.Network.Server qualified as Server
80- import Ouroboros.Network.Snocket (LocalAddress , LocalSocket (.. ), RemoteAddress ,
87+ import Ouroboros.Network.Snocket (LocalAddress (.. ), LocalSocket (.. ),
88+ RemoteAddress , configureLocalSocketFileDescriptor ,
8189 localSocketFileDescriptor , makeLocalBearer , makeSocketBearer' )
8290import Ouroboros.Network.Snocket qualified as Snocket
8391import Ouroboros.Network.Socket (configureSocket , configureSystemdSocket )
@@ -164,6 +172,7 @@ runM Interfaces
164172 , diNtcSnocket
165173 , diNtcBearer
166174 , diNtcGetFileDescriptor
175+ , diNtcConfigureFileDescriptor
167176 , diRng
168177 , diDnsActions
169178 , diConnStateIdSupply
@@ -318,7 +327,7 @@ runM Interfaces
318327 mkLocalThread :: ThreadId m -> Either ntcFd ntcAddr -> m Void
319328 mkLocalThread mainThreadId localAddr = do
320329 labelThisThread " diffusion-local"
321- withLocalSocket tracer diNtcGetFileDescriptor diNtcSnocket localAddr
330+ withLocalSocket tracer diNtcGetFileDescriptor diNtcConfigureFileDescriptor diNtcSnocket localAddr
322331 $ \ localSocket -> do
323332 localInbInfoChannel <- newInformationChannel
324333
@@ -912,7 +921,7 @@ run extraParams tracers args apps = do
912921--
913922
914923mkInterfaces :: IOManager
915- -> Tracer IO (DiffusionTracer ntnAddr ntcAddr )
924+ -> Tracer IO (DiffusionTracer ntnAddr LocalAddress )
916925 -> DiffTime
917926 -> IO (Interfaces Socket
918927 RemoteAddress
@@ -921,7 +930,6 @@ mkInterfaces :: IOManager
921930 Resolver
922931 IO )
923932mkInterfaces iocp tracer egressPollInterval = do
924-
925933 diRng <- newStdGen
926934 diConnStateIdSupply <- atomically $ CM. newConnStateIdSupply Proxy
927935
@@ -941,11 +949,44 @@ mkInterfaces iocp tracer egressPollInterval = do
941949 diNtcSnocket = Snocket. localSnocket iocp,
942950 diNtcBearer = makeLocalBearer,
943951 diNtcGetFileDescriptor = localSocketFileDescriptor,
952+ diNtcConfigureFileDescriptor = \ sock addr -> do
953+ configureLocalSocketFileDescriptor sock addr
954+ checkLocalSocketDirectory tracer addr,
944955 diDnsActions = RootPeersDNS. ioDNSActions,
945956 diRng,
946957 diConnStateIdSupply
947958 }
948959
960+ -- | Trace a warning if the parent directory of a local-socket path has
961+ -- @group@ or @other@ write permission. A @0600@ socket inside such a
962+ -- directory is still vulnerable to manipulation by another local user
963+ -- with write access to that directory.
964+ --
965+ -- No-op on Windows (named pipes do not live in a POSIX-permissioned
966+ -- directory) and on WASM (WASI does not implement the POSIX permission
967+ -- model in any meaningful way).
968+ checkLocalSocketDirectory
969+ :: Tracer IO (DiffusionTracer ntnAddr LocalAddress )
970+ -> LocalAddress
971+ -> IO ()
972+ #if defined(mingw32_HOST_OS) || defined(wasm32_HOST_ARCH)
973+ checkLocalSocketDirectory _ _ = return ()
974+ #else
975+ checkLocalSocketDirectory tracer addr@ (LocalAddress path) = do
976+ let dir = parentDirectory path
977+ st <- Unix. getFileStatus dir
978+ let mode = Unix. fileMode st
979+ writeMask = Unix. groupWriteMode .|. Unix. otherWriteMode
980+ when (Unix. intersectFileModes mode writeMask /= Unix. nullFileMode) $
981+ traceWith tracer (InsecureLocalSocketDirectory addr (fromIntegral mode))
982+ where
983+ parentDirectory :: FilePath -> FilePath
984+ parentDirectory p = case break (== ' /' ) (reverse p) of
985+ (_, ' /' : revParent) | not (null revParent) -> reverse revParent
986+ (_, ' /' : _) -> " /"
987+ _ -> " ."
988+ #endif
989+
949990--
950991-- Data flow
951992--
0 commit comments