Browse Source

[Tools] Multiple bug fixes of Graphene Secure Container (GSC) tool

- Forward container's LD_LIBRARY_PATH to the generated manifest
- Handle special library names when generating trusted files (libxxx-xxx.so)
- Add more standard files/directories to the generated manifest
Li Lei 4 years ago
parent
commit
030a088892
2 changed files with 137 additions and 115 deletions
  1. 73 56
      Tools/gen_manifest
  2. 64 59
      Tools/gsce

+ 73 - 56
Tools/gen_manifest

@@ -1,10 +1,9 @@
 #!/usr/bin/env python2
-
 import os
 import sys
 import subprocess
 import re
-from shutil import copyfile
+
 runtime_libs = ['libc',
                 'libdl',
                 'libm',
@@ -14,94 +13,112 @@ runtime_libs = ['libc',
                 'libresolv',
                 'librt']
 
-def parse_libs (bin_path) :
-  print (bin_path)
+
+def parse_libs(bin_path):
   ldd_out = subprocess.check_output(['ldd', bin_path])
   lib_list = []
   for line in ldd_out.splitlines():
     match = re.match(r'\t(.*) => (.*) \(0x', line)
     if match and match.group(1) and match.group(2):
-      full_lib_name = match.group(1)
-      name_match = re.match(r'([\w\d]*)(\.*)(.*)', full_lib_name)
+      name_match = re.match(r'([\w\d]*)(-*)([\w\d]*)(\.*)(.*)', match.group(1))
       if name_match:
         lib_name = name_match.group(1)
-        lib_path = match.group(2)
-        if lib_name not in runtime_libs :
-          lib_list.append((name_match.group(1), match.group(2)))
+
+        # library can be formatted as libxxx-xxx.so which is invalid format in
+        # the manifest, so reformat to libxxx_xxx as the option key
+        if name_match.group(2) == '-' and name_match.group(3):
+          lib_name += '_' + name_match.group(3)
+
+        if lib_name not in runtime_libs:
+          lib_list.append((lib_name, match.group(2)))
+
   return lib_list
 
-def make_exec(path) :
+
+def make_executable(path):
   mode = os.stat(path).st_mode
   mode |= (mode & 0o444) >> 2    # copy R bits to X
   os.chmod(path, mode)
 
-def gen_manifest(app_name, bin_name, g_path) :
-  m_path = g_path + '/LibOS/shim/test/apps/' + app_name + "/" + app_name +"." + "manifest"
-  print (m_path)
-  mf = open(m_path, "w")
-  make_exec(m_path)
-  mf.write("#!" + g_path + "/Runtime/pal_loader \n")
-  mf.write("loader.preload = file:../../../../../Runtime/libsysdb.so \n")
 
-  # Get Path of Binary
+def gen_manifest(app_name, bin_name, g_path):
+  m_path = g_path + '/LibOS/shim/test/apps/' + app_name + '/' + app_name + '.' + 'manifest'
+  print('generating manifest: ' + m_path)
+
+  mf = open(m_path, 'w')
+  make_executable(m_path)
+
+  mf.write('#!' + g_path + '/Runtime/pal_loader\n')
+  mf.write('loader.preload = file:../../../../../Runtime/libsysdb.so\n')
+
+  # Get path of binary
   bin_path = subprocess.check_output(['which', bin_name]).strip()
   mf.write('loader.exec = file:' + bin_path + '\n')
   mf.write('loader.execname = ' + bin_name + '\n')
-  mf.write('loader.env.LD_LIBRARY_PATH = /graphene:/graphene/resolv:/host:/usr/local/lib:/usr/lib:/usr/lib/x86_64-linux-gnu \n')
-  mf.write('loader.env.PATH = /usr/local/bin:/usr/bin:/bin \n' +
-           'loader.env.USERNAME = \n' +
-           'loader.env.PWD = \n' +
-           'loader.debug_type = none \n')
+  mf.write('loader.env.LD_LIBRARY_PATH = /graphene:/graphene/resolv:/host:/usr/local/lib:/usr/lib:/usr/lib/x86_64-linux-gnu')
+
+  if 'LD_LIBRARY_PATH' in os.environ and os.environ['LD_LIBRARY_PATH']:
+    mf.write(':' + os.environ['LD_LIBRARY_PATH'])
+  mf.write('\n')
+
+  mf.write('loader.env.PATH = /usr/local/bin:/usr/bin:/bin\n' +
+           'loader.env.USERNAME =\n' +
+           'loader.env.PWD =\n' +
+           'loader.debug_type = none\n')
   mf.write('\n')
 
   # File system setting
-  mf.write('fs.mount.lib1.type = chroot \n' +
-           'fs.mount.lib1.path = /graphene \n' +
-           'fs.mount.lib1.uri = file:../../../../../Runtime \n \n')
+  mf.write('fs.mount.lib1.type = chroot\n' +
+           'fs.mount.lib1.path = /graphene\n' +
+           'fs.mount.lib1.uri = file:../../../../../Runtime\n\n')
 
-  mf.write('fs.mount.lib2.type = chroot \n' +
-           'fs.mount.lib2.path = /host \n' +
-	   'fs.mount.lib2.uri = file:/lib/x86_64-linux-gnu \n \n')
+  mf.write('fs.mount.lib2.type = chroot\n' +
+           'fs.mount.lib2.path = /host\n' +
+           'fs.mount.lib2.uri = file:/lib/x86_64-linux-gnu\n\n')
 
-  mf.write('fs.mount.bin.type = chroot \n' +
-	   'fs.mount.bin.path = /bin \n' +
-	   'fs.mount.bin.uri = file:/bin \n \n')
+  mf.write('fs.mount.bin.type = chroot\n' +
+           'fs.mount.bin.path = /bin\n' +
+           'fs.mount.bin.uri = file:/bin\n\n')
 
-  mf.write('fs.mount.usr.type = chroot \n' +
-	   'fs.mount.usr.path = /usr \n' +
-	   'fs.mount.usr.uri = file:/usr \n \n')
+  mf.write('fs.mount.usr.type = chroot\n' +
+           'fs.mount.usr.path = /usr\n' +
+           'fs.mount.usr.uri = file:/usr\n\n')
 
-  mf.write('fs.mount.etc.type = chroot \n' +
-	   'fs.mount.etc.path = /etc \n' +
-	   'fs.mount.etc.uri = file: \n \n')
+  mf.write('fs.mount.etc.type = chroot\n' +
+           'fs.mount.etc.path = /etc\n' +
+           'fs.mount.etc.uri = file:\n\n')
 
-  # Set Dependent Libraries
+  mf.write('fs.mount.opt.type = chroot\n' +
+           'fs.mount.opt.path = /opt\n' +
+           'fs.mount.opt.uri = file:\n\n')
 
-  mf.write('sgx.trusted_files.ld = file:../../../../../Runtime/ld-linux-x86-64.so.2 \n' +
-           'sgx.trusted_files.libc = file:../../../../../Runtime/libc.so.6 \n' +
-           'sgx.trusted_files.libdl = file:../../../../../Runtime/libdl.so.2 \n' +
-           'sgx.trusted_files.libm = file:../../../../../Runtime/libm.so.6 \n' +
-           'sgx.trusted_files.libpthread = file:../../../../../Runtime/libpthread.so.0 \n' +
-           'sgx.trusted_files.libutil = file:../../../../../Runtime/libutil.so.1 \n' +
-           'sgx.trusted_files.libnss3 = file:../../../../../Runtime/libnss_dns.so.2 \n' +
-           'sgx.trusted_files.libresolv = file:../../../../../Runtime/libresolv.so.2 \n')
+  # Set Dependent Libraries
+  mf.write('sgx.trusted_files.ld = file:../../../../../Runtime/ld-linux-x86-64.so.2\n' +
+           'sgx.trusted_files.libc = file:../../../../../Runtime/libc.so.6\n' +
+           'sgx.trusted_files.libdl = file:../../../../../Runtime/libdl.so.2\n' +
+           'sgx.trusted_files.libm = file:../../../../../Runtime/libm.so.6\n' +
+           'sgx.trusted_files.libpthread = file:../../../../../Runtime/libpthread.so.0\n' +
+           'sgx.trusted_files.libutil = file:../../../../../Runtime/libutil.so.1\n' +
+           'sgx.trusted_files.libnss_dns = file:../../../../../Runtime/libnss_dns.so.2\n' +
+           'sgx.trusted_files.libresolv = file:../../../../../Runtime/libresolv.so.2\n' +
+           'sgx.trusted_files.librt = file:../../../../../Runtime/librt.so.1\n')
 
   lib_list = parse_libs(bin_path)
-  for lib_name, lib_path in lib_list :
-    print ("lib name: " + lib_name)
-    print ("lib path: " + lib_path)
+  for lib_name, lib_path in lib_list:
+    print('lib name: ' + lib_name)
+    print('lib path: ' + lib_path)
     mf.write('sgx.trusted_files.' + lib_name + ' = file:' + lib_path + '\n')
-
   mf.write('\n')
 
-  #	   'sgx.allowed_files.usr = file:/usr \n')
-
   mf.close()
 
-if __name__ == "__main__":
+
+if __name__ == '__main__':
   if len(sys.argv) != 4:
-   print ("Usage: gen_manifest [App Name] [bin_name] [Graphene Path]")
-   exit()
+    print('Usage: gen_manifest [application name] [actual binary name] [path to graphene]')
+    print('  e.g. gen_manifest apache httpd /home/me/graphene')
+    exit(1)
+
   app_name = sys.argv[1]
   bin_name = sys.argv[2]
   g_path = sys.argv[3]

+ 64 - 59
Tools/gsce

@@ -3,11 +3,10 @@ import sys,os
 import subprocess
 import re
 
-
-def gen_dockerfile( image_name, app_name, bin_name, proj_dir) :
-  if not os.path.exists(proj_dir + "/Tools/build") :
-    os.makedirs(proj_dir + "/Tools/build")
-  df =open(proj_dir + "/Tools/build/Dockerfile" + '.' + app_name, 'w')
+def gen_dockerfile( image_name, app_name, bin_name, proj_dir):
+  if not os.path.exists(proj_dir + '/Tools/build'):
+    os.makedirs(proj_dir + '/Tools/build')
+  df =open(proj_dir + '/Tools/build/Dockerfile' + '.' + app_name, 'w')
   df.write('# This file is auto-generated, any edits will be overwritten\n')
 
   df.write('\n')
@@ -16,107 +15,112 @@ def gen_dockerfile( image_name, app_name, bin_name, proj_dir) :
   df.write('\n')
 
   # SWITCH to ROOT
-  df.write('# SWITCH to root \n')
-  df.write('USER root \n')
-  df.write('\n')
+  df.write('# SWITCH to root\n')
+  df.write('USER root\n\n')
 
   # DOWNLOAD dependencies
   df.write('# Download dependencies\n')
-  df.write('RUN apt-get update \\\n')
-  df.write('    && apt-get install -y openssl libjemalloc-dev python python-pip python-dev \\\n')
-  df.write('    && pip install protobuf \\\n')
-  df.write('    && pip install pycrypto \n')
+  df.write('RUN apt-get update && \\\n')
+  df.write('    apt-get install -y openssl libjemalloc-dev python python-pip python-dev\n')
+  df.write('RUN pip install protobuf && \\\n')
+  df.write('    pip install pycrypto\n')
 
-  df.write('# Temporal fixes for Dependencies Issue #1: libcrypto.so.1.0.0 and libssl.so.1.0.0 have different locations \n')
-  df.write('RUN ln -s /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 \\\n')
-  df.write('    && ln -s /usr/lib/x86_64-linux-gnu/libssl.so.1.0.0 /lib/x86_64-linux-gnu/libssl.so.1.0.0 \n')
+  df.write('# Temporal fixes for Dependencies Issue #1: libcrypto.so.1.0.0 and libssl.so.1.0.0 have different locations\n')
+  if not os.path.isfile('/lib/x86_64-linux-gnu/libcrypto.so.1.0.0'):
+    df.write('RUN ln -s /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0 /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 \\\n')
+  if not os.path.isfile('/lib/x86_64-linux-gnu/libssl.so.1.0.0'):
+    df.write('RUN ln -s /usr/lib/x86_64-linux-gnu/libssl.so.1.0.0 /lib/x86_64-linux-gnu/libssl.so.1.0.0\n')
 
   # SETUP Directory Structure
-  print "cwd: "+ proj_dir
-  df.write('# Setup Directory Structure \n')
+  df.write('# Setup Directory Structure\n')
   df.write('RUN mkdir -p ' + proj_dir + '/LibOS/shim/test/apps/' + app_name + ' \\\n')
-  df.write('    && mkdir -p ' + proj_dir + '/Pal/src/host/Linux-SGX/signer \\\n')
-  df.write('    && mkdir -p ' + proj_dir + '/Runtime \\\n')
-  df.write('    && mkdir /gbin \n')
+  df.write(' && mkdir -p ' + proj_dir + '/Pal/src/host/Linux-SGX/signer \\\n')
+  df.write(' && mkdir -p ' + proj_dir + '/Runtime \\\n')
+  df.write(' && mkdir /gbin\n')
 
   # COPY system files
-  df.write('# Copy system files \n')
-  df.write('COPY Runtime/* ' + proj_dir + '/Runtime/ \n')
-  df.write('COPY Pal/src/Makefile.Host ' + proj_dir + '/Pal/src/Makefile.Host \n')
-  df.write('COPY Pal/src/host/Linux-SGX/signer/* ' + proj_dir + '/Pal/src/host/Linux-SGX/signer/ \n')
+  df.write('# Copy system files\n')
+  df.write('COPY Runtime/* ' + proj_dir + '/Runtime/\n')
+  df.write('COPY Pal/src/Makefile.Host ' + proj_dir + '/Pal/src/Makefile.Host\n')
+  df.write('COPY Pal/src/host/Linux-SGX/signer/* ' + proj_dir + '/Pal/src/host/Linux-SGX/signer/\n')
 
   # COPY tools for building app instance
   df.write('# Copy tools for building app instance\n')
-  df.write('COPY Tools/build/tools/* /gbin/ \n')
-  df.write('COPY Tools/gen_manifest /gbin/  \n')
+  df.write('COPY Tools/build/tools/* /gbin/\n')
+  df.write('COPY Tools/gen_manifest /gbin/\n')
 
   # Generating manifest file for target app
-  df.write('# Generating manifest for target app \n')
+  df.write('# Generating manifest for target app\n')
   df.write('RUN /gbin/gen_manifest ' + app_name + ' ' + bin_name + ' ' + proj_dir + '\n')
 
   # Sign Enclave
-  df.write('# Signing Enclave \n')
-  df.write('RUN cd ' + proj_dir + '/LibOS/shim/test/apps/' + app_name + ' && \ \n'
+  df.write('# Signing Enclave\n')
+  df.write('RUN cd ' + proj_dir + '/LibOS/shim/test/apps/' + app_name + ' && \\\n'
            '    '+ proj_dir + '/Pal/src/host/Linux-SGX/signer/pal-sgx-sign -libpal ' + proj_dir +
            '/Pal/src/host/Linux-SGX/../../../../Runtime/libpal-Linux-SGX.so -key ' + proj_dir +
            '/Pal/src/host/Linux-SGX/signer/enclave-key.pem -output ' + app_name + '.manifest.sgx ' +
-           '-manifest ' + app_name + '.manifest \n')
+           '-manifest ' + app_name + '.manifest\n')
   # Remove signing key
-  df.write('# Removing key after signing \n')
-  # TODO
+  df.write('# Removing key after signing\n')
 
   # Overwrite Entry Point
-  df.write('ENTRYPOINT  ["/bin/bash", "/gbin/app_exec"] \n')
+  df.write('ENTRYPOINT  ["/bin/bash", "/gbin/app_exec"]\n')
   df.close()
 
-def make_exec(path) :
+def make_executable(path):
   mode = os.stat(path).st_mode
   mode |= (mode & 0o444) >> 2    # copy R bits to X
   os.chmod(path, mode)
 
-def gen_app_executor(app_name, bin_cmd, proj_dir) :
-  if not os.path.exists(proj_dir + "/Tools/build/tools") :
-    os.makedirs(proj_dir + "/Tools/build/tools")
+def gen_app_executor(app_name, bin_cmd, proj_dir):
+  if not os.path.exists(proj_dir + '/Tools/build/tools'):
+    os.makedirs(proj_dir + '/Tools/build/tools')
+
+  e_path = proj_dir + '/Tools/build/tools/app_exec'
+  ef = open(e_path, 'w')
+  make_executable(e_path)
 
-  e_path = proj_dir + "/Tools/build/tools/app_exec"
-  print "e_path: " + e_path
-  ef = open(e_path, "w")
-  make_exec(e_path)
   ef.write('#!/usr/bin/env bash\n\n')
   ef.write('cd ' + proj_dir + '/LibOS/shim/test/apps/' + app_name +'\n')
-  ef.write('# Generate EINITOKEN \n')
+  ef.write('# Generate EINITOKEN\n')
   ef.write(proj_dir + '/Pal/src/host/Linux-SGX/signer/pal-sgx-get-token -output '
-           + app_name + '.token -sig ' + app_name + '.sig \n')
-  ef.write('# Run the application \n')
+           + app_name + '.token -sig ' + app_name + '.sig\n')
+  ef.write('# Run the application\n')
   ef.write('SGX=1 ./' + app_name + '.manifest.sgx ' + bin_cmd + '\n')
 
   ef.close()
 
-if __name__ == "__main__":
+if __name__ == '__main__':
   if len(sys.argv) < 3:
-    print "Usage: gsce run [Image name] "
+    print('Usage: gsce run [Image name]')
     exit()
 
   image_name = sys.argv[-1]
   image_match = re.match(r'([^:]*)(:*)(.*)', image_name)
-  if image_match :
+  if image_match:
     app_name = image_match.group(1)
-  print "app_name: " + app_name
-  inspect_cmd = "sudo docker inspect --format '{{.Config.Cmd}}' " + image_name
+
+  # application name may contain '/', remove it
+  app_name = app_name.split('/')[0]
+
+  inspect_cmd = 'sudo docker inspect --format \'{{.Config.Cmd}}\' ' + image_name
   res = subprocess.check_output(inspect_cmd, shell=True).strip()
-  print res
+
+  # Docker image may execute '[/bin/sh -c command]', replace with just '[command]'
+  if res.startswith('[/bin/sh -c '):
+    res = '[' + res[len('[/bin/sh -c '):]
+
   match = re.match(r'\[([^\s]*)\s*(.*)\]', res)
   bin_name = match.group(1)
-  if match.group(2) :
+  bin_cmd = ''
+  if match.group(2):
     bin_cmd = match.group(2)
-  else :
-    bin_cmd = ""
-  print "bin_name: " + bin_name + " bin_cmd: " + bin_cmd
-  # Store the rest arguments as docker run arguments
-  docker_str = " " + " ".join(sys.argv[2:-1])
+
+  # Store the rest arguments as Docker run arguments
+  docker_str = ' ' + ' '.join(sys.argv[2:-1])
 
   # print image_cmd
-  proj_dir = os.path.abspath(os.getcwd() + "/../")
+  proj_dir = os.path.abspath(os.getcwd() + '/../')
 
   # STEP 1: Generating Dockerfile
   gen_dockerfile(image_name, app_name, bin_name, proj_dir)
@@ -126,7 +130,8 @@ if __name__ == "__main__":
 
   # STEP 3: Building new docker image with generated Dockerfile
   os.chdir('..')
-  os.system("sudo docker build -f Tools/build/Dockerfile." + app_name + " -t gsc_" + app_name + " .\n")
+  os.system('sudo docker build -f Tools/build/Dockerfile.' + app_name + ' -t gsc_' + app_name + ' .\n')
 
   # STEP 4: Run GSC with the target app
-  os.system("sudo docker run -i -t" + docker_str +" --device=/dev/gsgx --device=/dev/isgx -v /var/run/aesmd/aesm.socket:/var/run/aesmd/aesm.socket gsc_"+app_name+"\n")
+  os.system('sudo docker run -i -t' + docker_str +' --device=/dev/gsgx --device=/dev/isgx ' +
+            '-v /var/run/aesmd/aesm.socket:/var/run/aesmd/aesm.socket gsc_' + app_name + '\n')