From b3fc087c8fabc48abd7810d7ece1f8dc2a609237 Mon Sep 17 00:00:00 2001 From: LiYang Date: Fri, 26 Aug 2016 21:20:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0seccomp=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=EF=BC=9B=E5=A2=9E=E5=8A=A0mmap=E8=A7=84?= =?UTF-8?q?=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rules/c_cpp/rule.c | 4 ++ tests/test.py | 1 + tests/testcase/integration/test.py | 10 +--- tests/testcase/seccomp/__init__.py | 0 tests/testcase/seccomp/mmap.c | 95 ++++++++++++++++++++++++++++++ tests/testcase/seccomp/test.py | 38 ++++++++++++ 6 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 tests/testcase/seccomp/__init__.py create mode 100644 tests/testcase/seccomp/mmap.c create mode 100644 tests/testcase/seccomp/test.py diff --git a/src/rules/c_cpp/rule.c b/src/rules/c_cpp/rule.c index c6dc963..f77a51b 100644 --- a/src/rules/c_cpp/rule.c +++ b/src/rules/c_cpp/rule.c @@ -31,6 +31,10 @@ int load_seccomp(void *dl_handler, struct config *_config) { if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_LE, 2)) != 0) { return LOAD_SECCOMP_FAILED; } + // mmap can write file, 5th args is fd + if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 1, SCMP_A5(SCMP_CMP_LE, 2)) != 0) { + return LOAD_SECCOMP_FAILED; + } if (seccomp_load(ctx) != 0) { return LOAD_SECCOMP_FAILED; } diff --git a/tests/test.py b/tests/test.py index 30bacad..d5fa818 100644 --- a/tests/test.py +++ b/tests/test.py @@ -3,5 +3,6 @@ from unittest import TestCase, main from testcase.integration.test import IntegrationTest from testcase.c_cpp.test import C_CPPJudgeTestCase +from testcase.seccomp.test import SeccompTest main() \ No newline at end of file diff --git a/tests/testcase/integration/test.py b/tests/testcase/integration/test.py index 6e68895..8ec8312 100644 --- a/tests/testcase/integration/test.py +++ b/tests/testcase/integration/test.py @@ -21,7 +21,7 @@ class IntegrationTest(base.BaseTestCase): "args": [], "env": ["env=judger_test", "test=judger"], "log_path": "judger_test.log", - "seccomp_rule_so_path": "/usr/lib/judger/librule_c_cpp.so", + "seccomp_rule_so_path": None, "uid": 0, "gid": 0} self.workspace = self.init_workspace("integration") @@ -156,7 +156,6 @@ class IntegrationTest(base.BaseTestCase): def test_real_time(self): config = self.config config["exe_path"] = self._compile_c("sleep.c") - config["seccomp_rule_so_path"] = None result = _judger.run(**config) self.assertEqual(result["result"], _judger.REAL_TIME_LIMIT_EXCEEDED) self.assertEqual(result["signal"], signal.SIGKILL) @@ -165,7 +164,6 @@ class IntegrationTest(base.BaseTestCase): def test_cpu_time(self): config = self.config config["exe_path"] = self._compile_c("while1.c") - config["seccomp_rule_so_path"] = None result = _judger.run(**config) self.assertEqual(result["result"], _judger.CPU_TIME_LIMIT_EXCEEDED) self.assertEqual(result["signal"], signal.SIGKILL) @@ -209,7 +207,6 @@ class IntegrationTest(base.BaseTestCase): def test_re2(self): config = self.config config["exe_path"] = self._compile_c("re2.c") - config["seccomp_rule_so_path"] = None result = _judger.run(**config) self.assertEqual(result["result"], _judger.RUNTIME_ERROR) self.assertEqual(result["signal"], signal.SIGSEGV) @@ -217,14 +214,12 @@ class IntegrationTest(base.BaseTestCase): def test_child_proc_cpu_time_limit(self): config = self.config config["exe_path"] = self._compile_c("child_proc_cpu_time_limit.c") - config["seccomp_rule_so_path"] = None result = _judger.run(**config) self.assertEqual(result["result"], _judger.CPU_TIME_LIMIT_EXCEEDED) def test_child_proc_real_time_limit(self): config = self.config config["exe_path"] = self._compile_c("child_proc_real_time_limit.c") - config["seccomp_rule_so_path"] = None result = _judger.run(**config) self.assertEqual(result["result"], _judger.REAL_TIME_LIMIT_EXCEEDED) self.assertEqual(result["signal"], signal.SIGKILL) @@ -242,7 +237,6 @@ class IntegrationTest(base.BaseTestCase): config = self.config config["exe_path"] = self._compile_c("uid_gid.c") config["output_path"] = config["error_path"] = self.output_path() - config["seccomp_rule_so_path"] = None config["uid"] = 65534 config["gid"] = 65534 result = _judger.run(**config) @@ -253,7 +247,6 @@ class IntegrationTest(base.BaseTestCase): def test_gcc_random(self): config = self.config config["exe_path"] = "/usr/bin/gcc" - config["seccomp_rule_so_path"] = None config["args"] = [os.path.join(os.path.dirname(os.path.abspath(__file__)), "gcc_random.c"), "-o", os.path.join(self.workspace, "gcc_random")] result = _judger.run(**config) @@ -264,7 +257,6 @@ class IntegrationTest(base.BaseTestCase): def test_cpp_meta(self): config = self.config config["exe_path"] = "/usr/bin/g++" - config["seccomp_rule_so_path"] = None config["args"] = [os.path.join(os.path.dirname(os.path.abspath(__file__)), "cpp_meta.cpp"), "-o", os.path.join(self.workspace, "cpp_meta")] result = _judger.run(**config) diff --git a/tests/testcase/seccomp/__init__.py b/tests/testcase/seccomp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/testcase/seccomp/mmap.c b/tests/testcase/seccomp/mmap.c new file mode 100644 index 0000000..43b3d98 --- /dev/null +++ b/tests/testcase/seccomp/mmap.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, const char *argv[]) +{ + const char *text = "Hello world"; + + /* Open a file for writing. + * - Creating the file if it doesn't exist. + * - Truncating it to 0 size if it already exists. (not really needed) + * + * Note: "O_WRONLY" mode is not sufficient when mmaping. + */ + + const char *filepath = "/tmp/mmapped.bin"; + size_t i; + + int fd = open(filepath, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600); + + if (fd == -1) + { + perror("Error opening file for writing"); + exit(EXIT_FAILURE); + } + + // Stretch the file size to the size of the (mmapped) array of char + + size_t textsize = strlen(text) + 1; // + \0 null character + + if (lseek(fd, textsize-1, SEEK_SET) == -1) + { + close(fd); + perror("Error calling lseek() to 'stretch' the file"); + exit(EXIT_FAILURE); + } + + /* Something needs to be written at the end of the file to + * have the file actually have the new size. + * Just writing an empty string at the current file position will do. + * + * Note: + * - The current position in the file is at the end of the stretched + * file due to the call to lseek(). + * - An empty string is actually a single '\0' character, so a zero-byte + * will be written at the last byte of the file. + */ + + if (write(fd, "", 1) == -1) + { + close(fd); + perror("Error writing last byte of the file"); + exit(EXIT_FAILURE); + } + + + // Now the file is ready to be mmapped. + char *map = mmap(0, textsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + close(fd); + perror("Error mmapping the file"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < textsize; i++) + { + printf("Writing character %c at %zu\n", text[i], i); + map[i] = text[i]; + } + + // Write it now to disk + if (msync(map, textsize, MS_SYNC) == -1) + { + perror("Could not sync the file to disk"); + } + + // Don't forget to free the mmapped memory + if (munmap(map, textsize) == -1) + { + close(fd); + perror("Error un-mmapping the file"); + exit(EXIT_FAILURE); + } + + // Un-mmaping doesn't close the file, so we still need to do that. + close(fd); + + return 0; +} \ No newline at end of file diff --git a/tests/testcase/seccomp/test.py b/tests/testcase/seccomp/test.py new file mode 100644 index 0000000..ba4c19f --- /dev/null +++ b/tests/testcase/seccomp/test.py @@ -0,0 +1,38 @@ +# coding=utf-8 +import _judger +import signal +import os + +from .. import base + + +class SeccompTest(base.BaseTestCase): + def setUp(self): + print "Running", self._testMethodName + self.config = {"max_cpu_time": 1000, + "max_real_time": 3000, + "max_memory": 1024 * 1024 * 1024, + "max_process_number": 10, + "max_output_size": 1024 * 1024, + "exe_path": "/bin/ls", + "input_path": "/dev/null", + "output_path": "/dev/null", + "error_path": "/dev/null", + "args": [], + "env": ["env=judger_test", "test=judger"], + "log_path": "judger_test.log", + "seccomp_rule_so_path": None, + "uid": 0, + "gid": 0} + self.workspace = self.init_workspace("seccomp") + + def _compile_c(self, src_name): + return super(SeccompTest, self)._compile_c("seccomp/" + src_name) + + def test_mmap_write_file(self): + config = self.config + config["exe_path"] = self._compile_c("mmap.c") + config["seccomp_rule_so_path"] = "/usr/lib/judger/librule_c_cpp.so" + result = _judger.run(**config) + self.assertEqual(result["result"], _judger.RUNTIME_ERROR) + self.assertEqual(result["signal"], 31)