Skip to content

Commit

Permalink
mac: mirror the linux side by having a startup script. Also support g…
Browse files Browse the repository at this point in the history
…et_archive so that SSH will wait until the instance is ready.
  • Loading branch information
adamdoupe committed Sep 25, 2024
1 parent d9bd4de commit f6ad5ea
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 12 deletions.
5 changes: 4 additions & 1 deletion dojo_plugin/utils/mac_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,10 @@ def put_archive(self, path, data):
self.exec_run(f"cat - | tar -xvf - -C {shlex.quote(path)}", input=data.read())

def get_archive(self, path):
pass
exitcode, output = self.exec_run(f"tar -cf - {shlex.quote(path)}")
if exitcode != 0:
raise docker.errors.NotFound(f'Getting archive {path=} failed {exitcode=} {output=}')
return output



Expand Down
33 changes: 22 additions & 11 deletions sshd/mac_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def __init__(self, hostname=None, username=None, key_filename=None, guest_key_fi
def close(self):
pass # No persistent connection to close

def _ssh_exec(self, command, only_stdout=True, exception_on_fail=True, input=None, capture_output=True):
def _ssh_exec(self, command, only_stdout=True, exception_on_fail=True, input=None, capture_output=True, timeout_seconds=None):
ssh_command = ['ssh',
"-a",
"-o", "StrictHostKeychecking=no",
Expand All @@ -68,11 +68,11 @@ def _ssh_exec(self, command, only_stdout=True, exception_on_fail=True, input=Non
stdout_loc = None
stderr_loc = None

result = subprocess.run(ssh_command, stdout=stdout_loc, stderr=stderr_loc, input=input)
result = subprocess.run(ssh_command, stdout=stdout_loc, stderr=stderr_loc, input=input, timeout=timeout_seconds)
if result.returncode != 0:
if exception_on_fail:
error_msg = result.stdout.strip()
raise Exception(f'SSH {command=} {self.username=} {self.key_filename=} {self.hostname=} failed: {error_msg}')
raise Exception(f'SSH {ssh_command=} {self.username=} {self.key_filename=} {self.hostname=} {result=} {result.returncode=} failed: {error_msg}')
return result.returncode, result.stdout.strip() if result.stdout else b""


Expand Down Expand Up @@ -110,7 +110,8 @@ def create(self, image, entrypoint=None, name=None, hostname=None, user=None,
time.sleep(1)
# set up the timeout
container = MacContainer(self.client, vm)
container.exec_run(f"nohup bash -c 'sleep {MAC_TIMEOUT_SECONDS} && echo \"VM and all files going away in 5 minutes, better save now\" | wall && sleep 300 && echo \"VM and all files going away in 1 minute, last warning\" | wall && sleep 60 && shutdown -h now' > /dev/null &", user="0")
# disable and do on the image now
# container.exec_run(f"nohup bash -c 'sleep {MAC_TIMEOUT_SECONDS} && echo \"VM and all files going away in 5 minutes, better save now\" | wall && sleep 300 && echo \"VM and all files going away in 1 minute, last warning\" | wall && sleep 60 && shutdown -h now' > /dev/null &", user="0")
return container
else:
raise Exception(f'Error creating container: {image=} {name=} {output}')
Expand All @@ -137,10 +138,17 @@ def __init__(self, client, vm_info):

def remove(self, force=True):
# Kill the VM
command = f'{MAC_GUEST_CONTROL_FILE} kill-vm {self.id}'
exitcode, output = self.client._ssh_exec(command)
if b'Error' in output:
raise Exception(f'Error removing container: {output}')

# first try to shutdown the VM
try:
self.exec_run("shutdown -h now", "0", timeout_seconds=10)
except subprocess.TimeoutExpired:
# if that didn't work, kill it
if force:
command = f'{MAC_GUEST_CONTROL_FILE} kill-vm {self.id}'
exitcode, output = self.client._ssh_exec(command)
if b'Error' in output:
raise Exception(f'Error removing container: {output}')

def wait(self, condition='removed'):
# Wait until the VM is removed
Expand All @@ -160,7 +168,7 @@ def start(self):
pass

# returns exit_code, output
def exec_run(self, cmd, user=None, input=None, capture_output=True, **kwargs):
def exec_run(self, cmd, user=None, input=None, capture_output=True, timeout_seconds=None, **kwargs):
# SSH to the VM's IP address and run the command
if user == "0" or user == None:
# they want to run the command as root
Expand All @@ -169,7 +177,7 @@ def exec_run(self, cmd, user=None, input=None, capture_output=True, **kwargs):
# they want to run the command as hacker
cmd = f"exec sudo su - hacker -c {shlex.quote(cmd)}"
command = f"{MAC_GUEST_CONTROL_FILE} exec {self.id} {shlex.quote(cmd)}"
exitcode, output = self.client._ssh_exec(command, only_stdout=False, exception_on_fail=False, input=input, capture_output=capture_output)
exitcode, output = self.client._ssh_exec(command, only_stdout=False, exception_on_fail=False, input=input, capture_output=capture_output, timeout_seconds=timeout_seconds)
return exitcode, output

# execve shell
Expand Down Expand Up @@ -219,7 +227,10 @@ def put_archive(self, path, data):
self.exec_run(f"cat - | tar -xvf - -C {shlex.quote(path)}", input=data.read())

def get_archive(self, path):
pass
exitcode, output = self.exec_run(f"tar -cf - {shlex.quote(path)}")
if exitcode != 0:
raise docker.errors.NotFound(f'Getting archive {path=} failed {exitcode=} {output=}')
return output



Expand Down

0 comments on commit f6ad5ea

Please sign in to comment.