@@ -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,8 +84,10 @@ 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 ,
81- localSocketFileDescriptor , makeLocalBearer , makeSocketBearer' )
87+ import Ouroboros.Network.Snocket (LocalAddress (.. ), LocalSocket (.. ),
88+ RemoteAddress , configureLocalSocketFile ,
89+ configureLocalSocketFileDescriptor , localSocketFileDescriptor ,
90+ makeLocalBearer , makeSocketBearer' )
8291import Ouroboros.Network.Snocket qualified as Snocket
8392import Ouroboros.Network.Socket (configureSocket , configureSystemdSocket )
8493import Ouroboros.Network.Util (PrettyShow (.. ))
@@ -164,6 +173,8 @@ runM Interfaces
164173 , diNtcSnocket
165174 , diNtcBearer
166175 , diNtcGetFileDescriptor
176+ , diNtcConfigureSocketFileDescriptor
177+ , diNtcConfigureSocketFile
167178 , diRng
168179 , diDnsActions
169180 , diConnStateIdSupply
@@ -318,7 +329,10 @@ runM Interfaces
318329 mkLocalThread :: ThreadId m -> Either ntcFd ntcAddr -> m Void
319330 mkLocalThread mainThreadId localAddr = do
320331 labelThisThread " diffusion-local"
321- withLocalSocket tracer diNtcGetFileDescriptor diNtcSnocket localAddr
332+ withLocalSocket tracer diNtcGetFileDescriptor
333+ diNtcConfigureSocketFileDescriptor
334+ diNtcConfigureSocketFile
335+ diNtcSnocket localAddr
322336 $ \ localSocket -> do
323337 localInbInfoChannel <- newInformationChannel
324338
@@ -912,7 +926,7 @@ run extraParams tracers args apps = do
912926--
913927
914928mkInterfaces :: IOManager
915- -> Tracer IO (DiffusionTracer ntnAddr ntcAddr )
929+ -> Tracer IO (DiffusionTracer ntnAddr LocalAddress )
916930 -> DiffTime
917931 -> IO (Interfaces Socket
918932 RemoteAddress
@@ -921,7 +935,6 @@ mkInterfaces :: IOManager
921935 Resolver
922936 IO )
923937mkInterfaces iocp tracer egressPollInterval = do
924-
925938 diRng <- newStdGen
926939 diConnStateIdSupply <- atomically $ CM. newConnStateIdSupply Proxy
927940
@@ -941,11 +954,45 @@ mkInterfaces iocp tracer egressPollInterval = do
941954 diNtcSnocket = Snocket. localSnocket iocp,
942955 diNtcBearer = makeLocalBearer,
943956 diNtcGetFileDescriptor = localSocketFileDescriptor,
957+ diNtcConfigureSocketFileDescriptor = configureLocalSocketFileDescriptor,
958+ diNtcConfigureSocketFile = \ addr -> do
959+ configureLocalSocketFile addr
960+ checkLocalSocketDirectory tracer addr,
944961 diDnsActions = RootPeersDNS. ioDNSActions,
945962 diRng,
946963 diConnStateIdSupply
947964 }
948965
966+ -- | Trace a warning if the parent directory of a local-socket path has
967+ -- @group@ or @other@ write permission. A @0600@ socket inside such a
968+ -- directory is still vulnerable to manipulation by another local user
969+ -- with write access to that directory.
970+ --
971+ -- No-op on Windows (named pipes do not live in a POSIX-permissioned
972+ -- directory) and on WASM (WASI does not implement the POSIX permission
973+ -- model in any meaningful way).
974+ checkLocalSocketDirectory
975+ :: Tracer IO (DiffusionTracer ntnAddr LocalAddress )
976+ -> LocalAddress
977+ -> IO ()
978+ #if defined(mingw32_HOST_OS) || defined(wasm32_HOST_ARCH)
979+ checkLocalSocketDirectory _ _ = return ()
980+ #else
981+ checkLocalSocketDirectory tracer addr@ (LocalAddress path) = do
982+ let dir = parentDirectory path
983+ st <- Unix. getFileStatus dir
984+ let mode = Unix. fileMode st
985+ writeMask = Unix. groupWriteMode .|. Unix. otherWriteMode
986+ when (Unix. intersectFileModes mode writeMask /= Unix. nullFileMode) $
987+ traceWith tracer (InsecureLocalSocketDirectory addr (fromIntegral mode))
988+ where
989+ parentDirectory :: FilePath -> FilePath
990+ parentDirectory p = case break (== ' /' ) (reverse p) of
991+ (_, ' /' : revParent) | not (null revParent) -> reverse revParent
992+ (_, ' /' : _) -> " /"
993+ _ -> " ."
994+ #endif
995+
949996--
950997-- Data flow
951998--
0 commit comments