Explorar o código

[Pal/Linux-SGX] Implement new manifest option sgx.file_check_policy

The new option specifies the file check policy, determining how and which files
can be opened. Previously, there were only two strict options: sgx.trusted_files
and sgx.allowed_files, but they are not flexible enough (e.g., unknown files are
never allowed).

This commit introduces two policies:
- allow_all_but_log allows files other than trusted/allowed files to be opened
  but outputs a warning message. This is a convenient way to debug applications.
- strict disallows all files other than trusted/allowed files (just like the
  previous logic).
Jia Zhang %!s(int64=4) %!d(string=hai) anos
pai
achega
e9b988136d

+ 13 - 0
Documentation/oldwiki/Graphene-SGX-Manifest-Syntax.md

@@ -89,3 +89,16 @@ This syntax specifies the signatures of allowed child processes of the current a
 process creation, the enclave in the current (parent) process will attest the enclave in the child
 process, by comparing to the signatures of the trusted children. If the child process is not
 trusted, the enclave will refuse to communicate with it.
+
+### File Check Policy
+
+    sgx.file_check_policy=[strict|allow_all_but_log]
+    (Default: strict)
+
+This syntax specifies the file check policy, determining the behavior of authentication when
+opening files.
+By default, only files explicitly listed as _trusted_files_ or _allowed_files_ declared in the
+manifest are allowed for access. If the file check policy is `allow_all_but_log`, all files other
+than trusted and allowed are allowed for access, and Graphene-SGX emits a warning message for
+every such file. This is a convenient way to determine the set of files that the ported
+application uses.

+ 1 - 1
LibOS/shim/test/regression/Makefile

@@ -2,7 +2,7 @@ c_executables = $(patsubst %.c,%,$(wildcard *.c))
 cxx_executables = $(patsubst %.cpp,%,$(wildcard *.cpp))
 manifests = $(patsubst %.manifest.template,%.manifest,$(wildcard *.manifest.template)) manifest
 
-exec_target = $(c_executables) $(cxx_executables)
+exec_target = $(c_executables) $(cxx_executables) file_check_policy_strict.manifest file_check_policy_allow_all_but_log.manifest
 target = $(exec_target) $(manifests)
 
 clean-extra += clean-tmp

+ 27 - 0
LibOS/shim/test/regression/file_check_policy.c

@@ -0,0 +1,27 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char** argv) {
+    if (argc != 2) {
+        fprintf(stderr, "Usage: %s file_check_policy_testfile\n", argv[0]);
+        return 1;
+    }
+
+    FILE* fp = fopen(argv[1], "r");
+    if (!fp) {
+        perror("fopen failed");
+        return 2;
+    }
+
+    int reti = fclose(fp);
+    if (reti) {
+        perror("fclose failed");
+        return 3;
+    }
+
+    printf("file_check_policy succeeded\n");
+
+    return 0;
+}

+ 17 - 0
LibOS/shim/test/regression/file_check_policy_allow_all_but_log.manifest.template

@@ -0,0 +1,17 @@
+#!$(PAL)
+
+loader.exec = file:file_check_policy
+loader.preload = file:$(SHIMPATH)
+loader.env.LD_LIBRARY_PATH = /lib
+loader.debug_type = none
+
+fs.mount.lib.type = chroot
+fs.mount.lib.path = /lib
+fs.mount.lib.uri = file:$(LIBCDIR)
+
+sgx.file_check_policy = allow_all_but_log
+
+sgx.trusted_files.ld = file:$(LIBCDIR)/ld-linux-x86-64.so.2
+sgx.trusted_files.libc = file:$(LIBCDIR)/libc.so.6
+
+sgx.trusted_files.test = file:trusted_testfile

+ 17 - 0
LibOS/shim/test/regression/file_check_policy_strict.manifest.template

@@ -0,0 +1,17 @@
+#!$(PAL)
+
+loader.exec = file:file_check_policy
+loader.preload = file:$(SHIMPATH)
+loader.env.LD_LIBRARY_PATH = /lib
+loader.debug_type = none
+
+fs.mount.lib.type = chroot
+fs.mount.lib.path = /lib
+fs.mount.lib.uri = file:$(LIBCDIR)
+
+sgx.file_check_policy = strict
+
+sgx.trusted_files.ld = file:$(LIBCDIR)/ld-linux-x86-64.so.2
+sgx.trusted_files.libc = file:$(LIBCDIR)/libc.so.6
+
+sgx.trusted_files.test = file:trusted_testfile

+ 32 - 0
LibOS/shim/test/regression/test_libos.py

@@ -154,6 +154,38 @@ class TC_01_OpenMP(RegressionTestCase):
         # OpenMP simple for loop
         self.assertIn('first: 0, last: 9', stdout)
 
+@unittest.skipUnless(HAS_SGX,
+    'This test is only meaningful on SGX PAL because file-check-policy is '
+    'only relevant to SGX.')
+class TC_02_FileCheckPolicy(RegressionTestCase):
+    def test_000_strict_success(self):
+        manifest = self.get_manifest('file_check_policy_strict')
+        stdout, stderr = self.run_binary([manifest, 'trusted_testfile'])
+
+        self.assertIn('file_check_policy succeeded', stdout)
+
+    def test_001_strict_fail(self):
+        manifest = self.get_manifest('file_check_policy_strict')
+        try:
+            stdout, stderr = self.run_binary([manifest, 'unknown_testfile'])
+            self.fail('expected to return nonzero')
+        except subprocess.CalledProcessError as e:
+            self.assertEqual(e.returncode, 2, 'expected returncode == 2')
+
+    def test_002_allow_all_but_log_success(self):
+        manifest = self.get_manifest('file_check_policy_allow_all_but_log')
+        stdout, stderr = self.run_binary([manifest, 'unknown_testfile'])
+
+        self.assertIn('Allowing access to an unknown file due to file_check_policy settings: file:unknown_testfile', stderr)
+        self.assertIn('file_check_policy succeeded', stdout)
+
+    def test_003_allow_all_but_log_fail(self):
+        manifest = self.get_manifest('file_check_policy_allow_all_but_log')
+        stdout, stderr = self.run_binary([manifest, 'trusted_testfile'])
+
+        self.assertNotIn('Allowing access to an unknown file due to file_check_policy settings: file:trusted_testfile', stderr)
+        self.assertIn('file_check_policy succeeded', stdout)
+
 class TC_30_Syscall(RegressionTestCase):
     def test_000_getcwd(self):
         stdout, stderr = self.run_binary(['getcwd'])

+ 1 - 0
LibOS/shim/test/regression/trusted_testfile

@@ -0,0 +1 @@
+trusted_testfile

+ 1 - 0
LibOS/shim/test/regression/unknown_testfile

@@ -0,0 +1 @@
+unknown_testfile

+ 5 - 0
Pal/src/host/Linux-SGX/db_main.c

@@ -408,6 +408,11 @@ void pal_linux_main(char * uptr_args, uint64_t args_size,
         ocall_exit(rv, true);
     }
 
+    if ((rv = init_file_check_policy()) < 0) {
+        SGX_DBG(DBG_E, "Failed to load the file check policy: %d\n", rv);
+        ocall_exit(rv, true);
+    }
+
 #if PRINT_ENCLAVE_STAT == 1
     printf("                >>>>>>>> "
            "Enclave loading time =      %10ld milliseconds\n",

+ 50 - 13
Pal/src/host/Linux-SGX/enclave_framework.c

@@ -223,6 +223,7 @@ static LISTP_TYPE(trusted_file) trusted_file_list = LISTP_INIT;
 static struct spinlock trusted_file_lock = LOCK_INIT;
 static int trusted_file_indexes = 0;
 static bool allow_file_creation = 0;
+static int file_check_policy = FILE_CHECK_POLICY_STRICT;
 
 /* Assumes `path` is normalized */
 static bool path_is_equal_or_subpath(const struct trusted_file* tf,
@@ -317,21 +318,15 @@ int load_trusted_file (PAL_HANDLE file, sgx_stub_t ** stubptr,
 
     _DkSpinUnlock(&trusted_file_lock);
 
-    if (!tf)
-        return -PAL_ERROR_DENIED;
+    if (!tf || !tf->index) {
+        if (!tf) {
+            if (get_file_check_policy() != FILE_CHECK_POLICY_ALLOW_ALL_BUT_LOG)
+                return -PAL_ERROR_DENIED;
 
-    if (tf->index < 0)
-        return tf->index;
-
-#if CACHE_FILE_STUBS == 1
-    if (tf->index && tf->stubs) {
-        *stubptr = tf->stubs;
-        *sizeptr = tf->size;
-        return 0;
-    }
-#endif
+            pal_printf("Allowing access to an unknown file due to "
+                       "file_check_policy settings: %s\n", uri);
+        }
 
-    if (!tf->index) {
         *stubptr = NULL;
         PAL_STREAM_ATTR attr;
         ret = _DkStreamAttributesQuery(normpath, &attr);
@@ -339,9 +334,21 @@ int load_trusted_file (PAL_HANDLE file, sgx_stub_t ** stubptr,
             *sizeptr = attr.pending_size;
         else
             *sizeptr = 0;
+
         return 0;
     }
 
+    if (tf->index < 0)
+        return tf->index;
+
+#if CACHE_FILE_STUBS == 1
+    if (tf->stubs) {
+        *stubptr = tf->stubs;
+        *sizeptr = tf->size;
+        return 0;
+    }
+#endif
+
     int nstubs = tf->size / TRUSTED_STUB_SIZE +
                 (tf->size % TRUSTED_STUB_SIZE ? 1 : 0);
 
@@ -460,6 +467,16 @@ failed:
     return ret;
 }
 
+int get_file_check_policy ()
+{
+    return file_check_policy;
+}
+
+static void set_file_check_policy (int policy)
+{
+    file_check_policy = policy;
+}
+
 /*
  * A common helper function for copying and checking the file contents
  * from a buffer mapped outside the enclaves into an in-enclave buffer.
@@ -888,6 +905,26 @@ int init_trusted_children (void)
     return 0;
 }
 
+int init_file_check_policy (void)
+{
+    char cfgbuf[CONFIG_MAX];
+    ssize_t ret = get_config(pal_state.root_config, "sgx.file_check_policy",
+                             cfgbuf, CONFIG_MAX);
+
+    if (ret > 0) {
+        if (!strcmp_static(cfgbuf, "strict"))
+            set_file_check_policy(FILE_CHECK_POLICY_STRICT);
+        else if (!strcmp_static(cfgbuf, "allow_all_but_log"))
+            set_file_check_policy(FILE_CHECK_POLICY_ALLOW_ALL_BUT_LOG);
+        else
+            INIT_FAIL(PAL_ERROR_INVAL, "unknown file check policy");
+
+        SGX_DBG(DBG_S, "File check policy: %s\n", cfgbuf);
+    }
+
+    return 0;
+}
+
 #if 0
 void test_dh (void)
 {

+ 9 - 0
Pal/src/host/Linux-SGX/pal_linux.h

@@ -128,6 +128,15 @@ int init_trusted_files (void);
 int load_trusted_file
     (PAL_HANDLE file, sgx_stub_t ** stubptr, uint64_t * sizeptr, int create);
 
+enum {
+    FILE_CHECK_POLICY_STRICT = 0,
+    FILE_CHECK_POLICY_ALLOW_ALL_BUT_LOG,
+};
+
+int init_file_check_policy (void);
+
+int get_file_check_policy (void);
+
 int copy_and_verify_trusted_file (const char * path, const void * umem,
                     uint64_t umem_start, uint64_t umem_end,
                     void * buffer, uint64_t offset, uint64_t size,