@@ -234,21 +234,22 @@ def __init__(
234234 # to have a number in the [0, num_workers_on_this_machine) range.
235235 box_id = (1 + (shard % 64 )) * BOXES_PER_SHARD + box_index
236236
237- # We create a directory "home" inside the outer temporary directory,
238- # that will be bind-mounted to "/tmp" inside the sandbox (some
239- # compilers need "/tmp" to exist, and this is a cheap shortcut to
240- # create it). The sandbox also runs code as a different user, and so
241- # we need to ensure that they can read and write to the directory.
242- # But we don't want everybody on the system to, which is why the
243- # outer directory exists with no read permissions.
237+ self .box_id = box_id
238+
239+ # Tell isolate to get the sandbox ready. We do our best to cleanup
240+ # after ourselves, but we might have missed something if a previous
241+ # worker was interrupted in the middle of an execution, so we issue an
242+ # idempotent cleanup.
243+ self .cleanup ()
244+
245+ isolate_box_dir = self .initialize_isolate ()
246+
244247 self ._outer_dir = tempfile .mkdtemp (
245- dir = self .temp_dir , prefix = "cms-%s-" % ( self .name )
248+ dir = self .temp_dir , prefix = f "cms-{ self .name } -"
246249 )
247- self ._home = os .path .join (self ._outer_dir , "home" )
248- self ._home_dest = "/tmp"
249- os .mkdir (self ._home )
250+ self ._home = os .path .join (isolate_box_dir , "box" )
251+ self ._home_dest = "/box"
250252
251- self .exec_name = "isolate"
252253 # Used for -M - the meta file ends up in the outer directory. The
253254 # actual filename will be <info_basename>.<execution_number>.
254255 self .info_basename = os .path .join (self ._outer_dir , "run.meta" )
@@ -259,7 +260,6 @@ def __init__(
259260 self .cmd_file = os .path .join (self ._outer_dir , "commands.log" )
260261
261262 # Default parameters for isolate
262- self .box_id = box_id # -b
263263 self .chdir = self ._home_dest # -c
264264 self .dirs : list [tuple [str | None , str , str | None ]] = [] # -d
265265 self .preserve_env = False # -e
@@ -278,10 +278,6 @@ def __init__(
278278
279279 self .max_processes : int = 1
280280
281- self .allow_writing_all ()
282-
283- self .add_mapped_directory (self ._home , dest = self ._home_dest , options = "rw" )
284-
285281 # Create temporary directory on /dev/shm to prevent communication
286282 # between sandboxes.
287283 self .dirs .append ((None , "/dev/shm" , "tmp" ))
@@ -304,13 +300,6 @@ def __init__(
304300 # particular, the System.Native assembly.
305301 self .maybe_add_mapped_directory ("/etc/mono" , options = "noexec" )
306302
307- # Tell isolate to get the sandbox ready. We do our best to cleanup
308- # after ourselves, but we might have missed something if a previous
309- # worker was interrupted in the middle of an execution, so we issue an
310- # idempotent cleanup.
311- self .cleanup ()
312- self .initialize_isolate ()
313-
314303 def set_multiprocess (self , multiprocess : bool ):
315304 """Set the sandbox to (dis-)allow multiple threads and processes.
316305
@@ -707,32 +696,9 @@ def cleanup(self, delete: bool = False):
707696 delete: if True, also delete get_root_path() and everything it
708697 contains.
709698 """
710- # The user isolate assigns within the sandbox might have created
711- # subdirectories and files therein, making the user outside the sandbox
712- # unable to delete the whole tree. If the caller asked us to delete the
713- # sandbox, we first issue a chmod within isolate to make sure that we
714- # will be able to delete everything. If not, we leave the files as they
715- # are to avoid masking possible problems the admin wanted to debug.
716699
717700 exe = ["isolate" , "--box-id=%d" % self .box_id , "--cg" ]
718701
719- if delete :
720- # Ignore exit status as some files may be owned by our user
721- subprocess .call (
722- exe
723- + [
724- "--dir=%s=%s:rw" % (self ._home_dest , self ._home ),
725- "--run" ,
726- "--" ,
727- "/bin/chmod" ,
728- "777" ,
729- "-R" ,
730- self ._home_dest ,
731- ],
732- stdout = subprocess .DEVNULL ,
733- stderr = subprocess .STDOUT ,
734- )
735-
736702 # Tell isolate to cleanup the sandbox.
737703 subprocess .check_call (
738704 exe + ["--cleanup" ], stdout = subprocess .DEVNULL , stderr = subprocess .STDOUT
@@ -755,18 +721,24 @@ def archive(self, file_cacher: FileCacher) -> str | None:
755721
756722 with tempfile .TemporaryFile (dir = self .temp_dir ) as sandbox_archive :
757723 # Archive the working directory
758- content_path = self .get_root_path ()
759- try :
760- with tarfile .open (fileobj = sandbox_archive , mode = "w:gz" ) as tar_file :
761- tar_file .add (content_path , os .path .basename (content_path ))
762- except Exception :
763- logger .warning ("Failed to archive sandbox" , exc_info = True )
764- return None
724+ metadata_path = self .get_root_path ()
725+ box_dir = self ._home
726+ with tarfile .open (fileobj = sandbox_archive , mode = 'w:gz' ) as tar_file :
727+ try :
728+ # Add metadata files
729+ for x in os .listdir (metadata_path ):
730+ tar_file .add (os .path .join (metadata_path , x ), x )
731+ # Add the box directory
732+ tar_file .add (box_dir , "box" )
733+ except Exception :
734+ logger .warning (
735+ "Failed to add files to sandbox archive" , exc_info = True
736+ )
765737
766738 # Put archive to FS
767739 sandbox_archive .seek (0 )
768740 return file_cacher .put_file_from_fobj (
769- sandbox_archive , "Sandbox %s" % self .get_root_path ()
741+ sandbox_archive , f "Sandbox { self .get_root_path ()} "
770742 )
771743
772744 def add_mapped_directory (
@@ -800,55 +772,6 @@ def maybe_add_mapped_directory(
800772 src , dest , options , ignore_if_not_existing = True
801773 )
802774
803- def allow_writing_all (self ):
804- """Set permissions in such a way that any operation is allowed."""
805- os .chmod (self ._home , 0o777 )
806- for filename in os .listdir (self ._home ):
807- os .chmod (os .path .join (self ._home , filename ), 0o777 )
808-
809- def allow_writing_none (self ):
810- """Set permissions in such a way that the user cannot write anything."""
811- os .chmod (self ._home , 0o755 )
812- for filename in os .listdir (self ._home ):
813- os .chmod (os .path .join (self ._home , filename ), 0o755 )
814-
815- def allow_writing_only (self , inner_paths : list [str ]):
816- """Set permissions in so that the user can write only some paths.
817-
818- By default the user can only write to the home directory. This
819- method further restricts permissions so that it can only write
820- to some files inside the home directory.
821-
822- inner_paths: the only paths that the user is allowed to
823- write to; they should be "inner" paths (from the perspective
824- of the sandboxed process, not of the host system); they can
825- be absolute or relative (in which case they are interpreted
826- relative to the home directory); paths that point to a file
827- outside the home directory are ignored.
828-
829- """
830- outer_paths = []
831- for inner_path in inner_paths :
832- abs_inner_path = os .path .realpath (os .path .join (self ._home_dest , inner_path ))
833- # If an inner path is absolute (e.g., /fifo0/u0_to_m) then
834- # it may be outside home and we should ignore it.
835- if os .path .commonpath ([abs_inner_path , self ._home_dest ]) != self ._home_dest :
836- continue
837- rel_inner_path = os .path .relpath (abs_inner_path , self ._home_dest )
838- outer_path = os .path .join (self ._home , rel_inner_path )
839- outer_paths .append (outer_path )
840-
841- # If one of the specified file do not exists, we touch it to
842- # assign the correct permissions.
843- for path in outer_paths :
844- if not os .path .exists (path ):
845- open (path , "wb" ).close ()
846-
847- # Close everything, then open only the specified.
848- self .allow_writing_none ()
849- for path in outer_paths :
850- os .chmod (path , 0o722 )
851-
852775 def build_box_options (self ) -> list [str ]:
853776 """Translate the options defined in the instance to a string
854777 that can be postponed to isolate as an arguments list.
@@ -980,12 +903,10 @@ def _popen(
980903 "Executing program in sandbox with command: `%s'." ,
981904 pretty_print_cmdline (args ),
982905 )
983- # Temporarily allow writing new files.
984- prev_permissions = stat .S_IMODE (os .stat (self ._home ).st_mode )
985- os .chmod (self ._home , 0o770 )
986- with open (self .cmd_file , "at" , encoding = "utf-8" ) as commands :
987- commands .write ("%s\n " % (pretty_print_cmdline (args )))
988- os .chmod (self ._home , prev_permissions )
906+
907+ with open (self .cmd_file , "a" ) as commands :
908+ commands .write (pretty_print_cmdline (args ) + "\n " )
909+
989910 try :
990911 p = subprocess .Popen (
991912 args , stdin = stdin , stdout = stdout , stderr = stderr , close_fds = close_fds
@@ -1000,10 +921,12 @@ def _popen(
1000921
1001922 return p
1002923
1003- def initialize_isolate (self ):
924+ def initialize_isolate (self ) -> str :
1004925 """Initialize isolate's box."""
1005926 init_cmd = ["isolate" , "--box-id=%d" % self .box_id , "--cg" , "--init" ]
1006927 try :
1007- subprocess .check_call (init_cmd )
928+ return subprocess .run (
929+ init_cmd , check = True , capture_output = True , encoding = "utf-8"
930+ ).stdout .strip ()
1008931 except subprocess .CalledProcessError as e :
1009932 raise SandboxInterfaceException ("Failed to initialize sandbox" ) from e
0 commit comments