Skip to content

Commit d220ddb

Browse files
committed
fixup! [LibOS] Test-cases for SPLRB
Signed-off-by: g2flyer <[email protected]>
1 parent 7c2f305 commit d220ddb

File tree

7 files changed

+226
-0
lines changed

7 files changed

+226
-0
lines changed

libos/test/regression/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ tests = {
8484
'c_args': '-fopenmp',
8585
'link_args': '-fopenmp',
8686
},
87+
'pf_rollback': {},
8788
'pipe': {},
8889
'pipe_nonblocking': {},
8990
'pipe_ocloexec': {},
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/* SPDX-License-Identifier: LGPL-3.0-or-later */
2+
/* Copyright (C) 2024 Intel Corporation
3+
* Paweł Marczewski <[email protected]>
4+
* Michael Steiner <[email protected]>
5+
*/
6+
7+
/*
8+
* Tests for rollback protection of protected (encrypted) files
9+
*/
10+
11+
#include <assert.h>
12+
#include <err.h>
13+
#include <errno.h>
14+
#include <stdio.h>
15+
#include <stdlib.h>
16+
#include <string.h>
17+
18+
#include "common.h"
19+
#include "rw_file.h"
20+
21+
static const char message1[] = "first message\n";
22+
static const size_t message1_len = sizeof(message1) - 1;
23+
24+
static const char message2[] = "second message\n";
25+
static const size_t message2_len = sizeof(message2) - 1;
26+
27+
static_assert(sizeof(message1) != sizeof(message2), "the messages should have different lengths");
28+
29+
/* TODO: eventually remove below copy/paste/extract heap
30+
static int create_file(const char* path, const char* str, size_t len) {
31+
int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0600);
32+
if (fd < 0)
33+
err(1, "open %s", path);
34+
35+
ssize_t n = posix_fd_write(fd, str, len);
36+
if (n < 0)
37+
errx(1, "posix_fd_write %s", path);
38+
if ((size_t)n != len)
39+
errx(1, "written less bytes than expected into %s", path);
40+
41+
if (rename(path, path) != 0)
42+
err(1, "rename");
43+
44+
if (unlink(path) != 0)
45+
err(1, "unlink %s", path);
46+
47+
if (close(fd) != 0)
48+
err(1, "close %s", path);
49+
50+
}
51+
*/
52+
53+
/* dummy functions which are gdb break-point targets */
54+
#pragma GCC push_options
55+
#pragma GCC optimize("O0")
56+
static void adversary_save_file(const char* path) {}
57+
static void adversary_reset_file(const char* path) {}
58+
static void adversary_delete_file(const char* path) {}
59+
#pragma GCC pop_options
60+
61+
static void test_test(const char* path1, const char* path2) {
62+
adversary_save_file(path1);
63+
adversary_reset_file(path1);
64+
adversary_delete_file(path1);
65+
adversary_delete_file(path2);
66+
}
67+
68+
int main(int argc, char* argv[]) {
69+
setbuf(stdout, NULL);
70+
setbuf(stderr, NULL);
71+
72+
if (argc != 3)
73+
errx(1, "Usage: %s <file1> <file2>", argv[0]);
74+
75+
const char* path1 = argv[1];
76+
const char* path2 = argv[2];
77+
78+
test_test(path1, path2);
79+
printf("TEST OK\n");
80+
return 0;
81+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
set breakpoint pending on
2+
set pagination off
3+
set backtrace past-main on
4+
5+
# We want to check what happens in the child process after fork()
6+
set follow-fork-mode child
7+
8+
# Cannot detach after fork because of some bug in SGX version of GDB (GDB would segfault)
9+
set detach-on-fork off
10+
11+
break adversary_save_file
12+
commands
13+
python
14+
# extract interesting info from context
15+
test_function=gdb.selected_frame().older().name()
16+
operation=gdb.selected_frame().name()
17+
internal_path=gdb.selected_frame().read_var('path').string()
18+
external_path=re.sub(r'/tmp_enc/pm_[^/]*/', './tmp_enc/', internal_path)
19+
external_path_saved=external_path+"._saved_"
20+
21+
# execute and report result for pytest digestion
22+
try:
23+
import shutil
24+
shutil.copyfile(external_path, external_path_saved)
25+
print(f"OK: {test_function} in {operation}({internal_path})")
26+
except:
27+
print(f"FAIL: {test_function} in {operation}({internal_path})")
28+
end
29+
30+
continue
31+
end
32+
33+
break adversary_reset_file
34+
commands
35+
python
36+
# extract interesting info from context
37+
test_function=gdb.selected_frame().older().name()
38+
operation=gdb.selected_frame().name()
39+
internal_path=gdb.selected_frame().read_var('path').string()
40+
external_path=re.sub(r'/tmp_enc/pm_[^/]*/', './tmp_enc/', internal_path)
41+
external_path_saved=external_path+"._saved_"
42+
43+
# execute and report result for pytest digestion
44+
try:
45+
import shutil
46+
shutil.move(external_path_saved, external_path)
47+
print(f"OK: {test_function} in {operation}({internal_path})")
48+
except:
49+
print(f"FAIL: {test_function} in {operation}({internal_path})")
50+
end
51+
52+
continue
53+
end
54+
55+
break adversary_delete_file
56+
commands
57+
python
58+
# extract interesting info from context
59+
test_function=gdb.selected_frame().older().name()
60+
operation=gdb.selected_frame().name()
61+
internal_path=gdb.selected_frame().read_var('path').string()
62+
external_path=re.sub(r'/tmp_enc/pm_[^/]*/', './tmp_enc/', internal_path)
63+
external_path_saved=external_path+"._saved_"
64+
65+
# execute and report result for pytest digestion
66+
try:
67+
import pathlib
68+
pathlib.Path.unlink(external_path)
69+
print(f"OK: {test_function} in {operation}({internal_path})")
70+
except:
71+
print(f"FAIL: {test_function} in {operation}({internal_path})")
72+
end
73+
74+
continue
75+
end
76+
77+
break die_or_inf_loop
78+
commands
79+
echo EXITING GDB WITH A GRAMINE ERROR\n
80+
quit
81+
end
82+
83+
break exit
84+
commands
85+
echo EXITING GDB WITHOUT A GRAMINE ERROR\n
86+
quit
87+
end
88+
89+
run
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
loader.entrypoint = "file:{{ gramine.libos }}"
2+
libos.entrypoint = "{{ entrypoint }}"
3+
4+
loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr/{{ arch_libdir }}"
5+
loader.insecure__use_cmdline_argv = true
6+
7+
fs.mounts = [
8+
{ path = "/lib", uri = "file:{{ gramine.runtimedir(libc) }}" },
9+
{ path = "/{{ entrypoint }}", uri = "file:{{ binary_dir }}/{{ entrypoint }}" },
10+
{ path = "/bin", uri = "file:/bin" },
11+
12+
{ type = "encrypted", protection_mode = "strict", path = "/tmp_enc/pm_strict", uri = "file:tmp_enc", key_name = "my_custom_key" },
13+
{ type = "encrypted", protection_mode = "non-strict", path = "/tmp_enc/pm_non_strict", uri = "file:tmp_enc", key_name = "my_custom_key" },
14+
{ type = "encrypted", protection_mode = "none", path = "/tmp_enc/pm_none", uri = "file:tmp_enc", key_name = "my_custom_key" },
15+
]
16+
17+
sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '16' }}
18+
sgx.debug = true
19+
sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }}
20+
21+
22+
sgx.trusted_files = [
23+
"file:{{ gramine.libos }}",
24+
"file:{{ gramine.runtimedir(libc) }}/",
25+
"file:{{ binary_dir }}/{{ entrypoint }}",
26+
]
27+
28+
# See the `keys.c` test.
29+
fs.insecure__keys.default = "ffeeddccbbaa99887766554433221100"
30+
fs.insecure__keys.my_custom_key = "00112233445566778899aabbccddeeff"

libos/test/regression/test_libos.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,29 @@ def test_020_gdb_fork_and_access_file_bug(self):
13851385
with open('fork_and_access_file_testfile', 'w') as f:
13861386
f.write('fork_and_access_file_testfile')
13871387

1388+
def test_030_gdb_pf_rollback(self):
1389+
# To run this test manually, use:
1390+
# GDB=1 GDB_SCRIPT=pf_rollback.gdb gramine-[sgx|direct] pf_rollback <file1> <file2>
1391+
#
1392+
# This test checks rollback protection.
1393+
try:
1394+
file1='/tmp_enc/pm_strict/file1'
1395+
file2='/tmp_enc/pm_strict/file2'
1396+
stdout, _ = self.run_gdb(['pf_rollback', file1, file2], 'pf_rollback.gdb')
1397+
# TODO (MST): This test is not yet implemented.
1398+
# - loop for /tmp_enc/pm_strict, /tmp_enc/pm_non_strict, /tmp_enc/pm_none
1399+
# - define expected sequence for each test
1400+
self.assertIn('OK: test_test in adversary_save_file', stdout)
1401+
self.assertIn('OK: test_test in adversary_reset_file', stdout)
1402+
self.assertIn(f'OK: test_test in adversary_delete_file({file1})', stdout)
1403+
self.assertIn(f'OK: test_test in adversary_delete_file({file2})', stdout)
1404+
self.assertIn('EXITING GDB WITHOUT A GRAMINE ERROR', stdout)
1405+
self.assertNotIn('EXITING GDB WITH A GRAMINE ERROR', stdout)
1406+
finally:
1407+
# restore the trusted file contents (modified by the GDB script in this test)
1408+
with open('fork_and_access_file_testfile', 'w') as f:
1409+
f.write('fork_and_access_file_testfile')
1410+
13881411
class TC_80_Socket(RegressionTestCase):
13891412
def test_000_getsockopt(self):
13901413
stdout, _ = self.run_binary(['getsockopt'])

libos/test/regression/tests.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ manifests = [
8383
"munmap",
8484
"open_opath",
8585
"openmp",
86+
"pf_rollback",
8687
"pipe",
8788
"pipe_nonblocking",
8889
"pipe_ocloexec",

libos/test/regression/tests_musl.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ manifests = [
8585
"munmap",
8686
"open_opath",
8787
"openmp",
88+
"pf_rollback",
8889
"pipe",
8990
"pipe_nonblocking",
9091
"pipe_ocloexec",

0 commit comments

Comments
 (0)