@@ -722,10 +722,21 @@ extension Initd: Com_Apple_Containerization_Sandbox_V3_SandboxContext.SimpleServ
722722 async throws -> Com_Apple_Containerization_Sandbox_V3_FilesystemOperationResponse
723723 {
724724 let path = FilePath ( request. path)
725+ if !request. hasContainerID {
726+ throw ContainerizationError (
727+ . invalidArgument,
728+ message: " containerID is required "
729+ )
730+ }
731+
732+ let container = try await state. get ( container: request. containerID)
733+ let containerPid = container. pid
725734
726735 log. debug (
727736 " filesystemOperation " ,
728737 metadata: [
738+ " containerID " : " \( request. containerID) " ,
739+ " containerPid " : " \( containerPid) " ,
729740 " operation " : " \( String ( describing: request. operation) ) " ,
730741 " path " : " \( path) " ,
731742 ] )
@@ -734,6 +745,61 @@ extension Initd: Com_Apple_Containerization_Sandbox_V3_SandboxContext.SimpleServ
734745 throw RPCError ( code: . invalidArgument, message: " path must be absolute " )
735746 }
736747
748+ let selfMountFd = open ( " /proc/self/ns/mount " , O_RDONLY | O_DIRECTORY | O_CLOEXEC)
749+ if selfMountFd < 0 {
750+ let error = swiftErrno ( " open " )
751+ throw RPCError ( code: . internalError, message: " failed to open self mount namespace " , cause: error)
752+ }
753+
754+ defer {
755+ close ( selfMountFd)
756+ }
757+
758+ let containerMountFd = open ( " /proc/ \( containerPid) /ns/mount " , O_RDONLY | O_DIRECTORY | O_CLOEXEC)
759+ if containerMountFd < 0 {
760+ let error = swiftErrno ( " open " )
761+ throw RPCError ( code: . internalError, message: " failed to open container mount namespace " , cause: error)
762+ }
763+
764+ defer {
765+ close ( containerMountFd)
766+ }
767+
768+ var finfo = _stat_struct ( )
769+ let selfMountStat = fstat ( selfMountFd, & finfo)
770+ if selfMountStat != 0 {
771+ let error = swiftErrno ( " fstat " )
772+ throw RPCError ( code: . internalError, message: " failed to stat self mount namespace " , cause: error)
773+ }
774+ let selfInode = finfo. st_ino
775+
776+ let containerMountStat = fstat ( containerMountFd, & finfo)
777+ if containerMountStat != 0 {
778+ let error = swiftErrno ( " fstat " )
779+ throw RPCError ( code: . internalError, message: " failed to stat container mount namespace " , cause: error)
780+ }
781+ let containerInode = finfo. st_ino
782+
783+ if selfInode == containerInode {
784+ try doFilesystemOperation ( path: path, operation: request. operation)
785+ } else {
786+ try await self . runOnDedicatedThread {
787+ if unshare ( CLONE_FS) != 0 {
788+ let error = swiftErrno ( " unshare(CLONE_FS) " )
789+ throw RPCError ( code: . internalError, message: " failed to unshare filesystem namespace " , cause: error)
790+ }
791+ if setns ( containerMountFd, CLONE_NEWNS) != 0 {
792+ let error = swiftErrno ( " setns(CLONE_NEWNS) " )
793+ throw RPCError ( code: . internalError, message: " failed to enter container mount namespace " , cause: error)
794+ }
795+ try doFilesystemOperation ( path: path, operation: request. operation)
796+ }
797+ }
798+
799+ return . init( )
800+ }
801+
802+ private func doFilesystemOperation( path: FilePath , operation: Com_Apple_Containerization_Sandbox_V3_FilesystemOperationRequest . Operation ) throws {
737803 var finfo = _stat_struct ( )
738804 let rc = _stat ( path. string, & finfo)
739805 if rc != 0 {
@@ -753,7 +819,7 @@ extension Initd: Com_Apple_Containerization_Sandbox_V3_SandboxContext.SimpleServ
753819 defer { close ( fd) }
754820
755821 do {
756- switch request . operation {
822+ switch operation {
757823 case . freeze:
758824 try freezeFilesystem ( fd: fd)
759825 case . thaw:
@@ -1650,6 +1716,22 @@ extension Initd: Com_Apple_Containerization_Sandbox_V3_SandboxContext.SimpleServ
16501716 return error
16511717 }
16521718
1719+ private func runOnDedicatedThread< T: Sendable > (
1720+ _ work: @escaping ( ) throws -> T
1721+ ) async throws -> T {
1722+ try await withCheckedThrowingContinuation { continuation in
1723+ let thread = Thread {
1724+ do {
1725+ let result = try work ( )
1726+ continuation. resume ( returning: result)
1727+ } catch {
1728+ continuation. resume ( throwing: error)
1729+ }
1730+ }
1731+ thread. start ( )
1732+ }
1733+ }
1734+
16531735 // NOTE: This is just crummy. It works because today the assumption is
16541736 // every NIC in the root net namespace is for the container(s), but if we
16551737 // ever supported individual containers having their own NICs/IPs then this
0 commit comments