diff --git a/src/config/sandbox_config.h b/src/config/sandbox_config.h index 8f468aa6..2172c17e 100644 --- a/src/config/sandbox_config.h +++ b/src/config/sandbox_config.h @@ -39,6 +39,10 @@ class sandbox_config * @note Path must be accessible from inside of sandbox. */ std::string chdir = ""; + /** + * Working directory relative to the directory with the source files. + */ + std::string working_directory = ""; /** * Associative array of loaded limits with textual index identifying its hw group. */ diff --git a/src/helpers/config.cpp b/src/helpers/config.cpp index b3187941..f3157e5b 100644 --- a/src/helpers/config.cpp +++ b/src/helpers/config.cpp @@ -125,6 +125,9 @@ std::shared_ptr helpers::build_job_metadata(const YAML::Node &conf if (ctask["sandbox"]["chdir"] && ctask["sandbox"]["chdir"].IsScalar()) { sandbox->chdir = ctask["sandbox"]["chdir"].as(); } // can be ommited... no throw + if (ctask["sandbox"]["working-directory"] && ctask["sandbox"]["working-directory"].IsScalar()) { + sandbox->working_directory = ctask["sandbox"]["working-directory"].as(); + } // can be ommited... no throw // load limits... if they are supplied if (ctask["sandbox"]["limits"]) { diff --git a/src/helpers/filesystem.cpp b/src/helpers/filesystem.cpp index a607acf6..0a1b98aa 100644 --- a/src/helpers/filesystem.cpp +++ b/src/helpers/filesystem.cpp @@ -58,6 +58,21 @@ fs::path helpers::normalize_path(const fs::path &path) return result; } +bool helpers::check_relative(const fs::path &path) { + if(path.is_absolute()) { + return false; + } + + std::vector path_arr(path.begin(), path.end()); + for (auto &chunk : path_arr) { + if (chunk.string() == "..") { + return false; + } + } + + return true; +} + fs::path helpers::find_path_outside_sandbox(const std::string &inside_path, const std::string &sandbox_chdir, std::vector> &bound_dirs, diff --git a/src/helpers/filesystem.h b/src/helpers/filesystem.h index 7f476a32..a2fc7d10 100644 --- a/src/helpers/filesystem.h +++ b/src/helpers/filesystem.h @@ -25,6 +25,13 @@ namespace helpers */ fs::path normalize_path(const fs::path &path); + /** + * Check if given path is relative and do not contain any ".." element. + * @param path path to be checked + * @return true if path is relative and without double dots + */ + bool check_relative(const fs::path &path); + /** * Find path outside sandbox on real filesystem, based on given path inside sandbox. * @param inside path inside sandbox which will be resolved diff --git a/src/job/job.cpp b/src/job/job.cpp index 8e23096a..49a044c7 100644 --- a/src/job/job.cpp +++ b/src/job/job.cpp @@ -133,6 +133,11 @@ void job::build_job() limits = std::make_shared(worker_config_->get_limits()); } + // check relativeness of working directory + if (!helpers::check_relative(fs::path(sandbox->working_directory))) { + throw job_exception("Given working directory for task '" + task_meta->task_id + "' is not relative"); + } + // go through variables parsing sandbox->chdir = parse_job_var(sandbox->chdir); sandbox->std_input = parse_job_var(sandbox->std_input); diff --git a/src/job/job.h b/src/job/job.h index bae00dcc..afcded87 100644 --- a/src/job/job.h +++ b/src/job/job.h @@ -15,6 +15,7 @@ namespace fs = boost::filesystem; #include "spdlog/spdlog.h" #include "../helpers/logger.h" #include "../helpers/topological_sort.h" +#include "../helpers/filesystem.h" #include "../config/worker_config.h" #include "../config/job_metadata.h" #include "../config/task_metadata.h" diff --git a/src/tasks/external_task.cpp b/src/tasks/external_task.cpp index ac54f3b1..44b90995 100644 --- a/src/tasks/external_task.cpp +++ b/src/tasks/external_task.cpp @@ -13,7 +13,7 @@ namespace fs = boost::filesystem; external_task::external_task(const create_params &data) : task_base(data.id, data.task_meta), worker_config_(data.worker_conf), sandbox_(nullptr), sandbox_config_(data.task_meta->sandbox), limits_(data.limits), logger_(data.logger), temp_dir_(data.temp_dir), - source_dir_(data.source_path), working_dir_(data.working_path) + evaluation_dir_(data.source_path), working_dir_(data.working_path) { if (worker_config_ == nullptr) { throw task_exception("No worker configuration provided."); @@ -27,6 +27,14 @@ external_task::external_task(const create_params &data) throw task_exception("No sandbox configuration provided."); } + if (!sandbox_config_->working_directory.empty()) { + if (!helpers::check_relative(sandbox_config_->working_directory)) { + throw task_exception("Given working directory in sandbox config is not relative"); + } + + evaluation_dir_ = fs::path(data.source_path) / sandbox_config_->working_directory; + } + sandbox_check(); } @@ -53,9 +61,8 @@ void external_task::sandbox_init() { #ifndef _WIN32 if (task_meta_->sandbox->name == "isolate") { - auto data_dir = fs::path(source_dir_) / task_meta_->test_id; sandbox_ = std::make_shared( - sandbox_config_, *limits_, worker_config_->get_worker_id(), temp_dir_, data_dir.string(), logger_); + sandbox_config_, *limits_, worker_config_->get_worker_id(), temp_dir_, evaluation_dir_.string(), logger_); } #endif } @@ -124,7 +131,7 @@ void external_task::results_output_init() fs::path external_task::find_path_outside_sandbox(std::string file) { return helpers::find_path_outside_sandbox( - file, sandbox_config_->chdir, limits_->bound_dirs, (fs::path(source_dir_) / task_meta_->test_id).string()); + file, sandbox_config_->chdir, limits_->bound_dirs, evaluation_dir_.string()); } void external_task::get_results_output(std::shared_ptr result) diff --git a/src/tasks/external_task.h b/src/tasks/external_task.h index 5ddefd31..c88c6599 100644 --- a/src/tasks/external_task.h +++ b/src/tasks/external_task.h @@ -96,8 +96,8 @@ class external_task : public task_base std::shared_ptr logger_; /** Directory for temporary files */ std::string temp_dir_; - /** Directory where source codes for job are located */ - fs::path source_dir_; + /** Directory outside sandbox where task will be executed */ + fs::path evaluation_dir_; /** Directory binded to the sandbox as default working dir */ fs::path working_dir_; /** After execution delete stdout file produced by sandbox */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index df8beb37..7a1ed62a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -87,6 +87,7 @@ add_test_suite(job ${HELPERS_DIR}/topological_sort.cpp ${HELPERS_DIR}/logger.cpp ${HELPERS_DIR}/config.cpp + ${HELPERS_DIR}/filesystem.cpp ${JOB_DIR}/job.cpp job.cpp ) diff --git a/tests/filesystem.cpp b/tests/filesystem.cpp index 4a1091b9..933d7113 100644 --- a/tests/filesystem.cpp +++ b/tests/filesystem.cpp @@ -32,6 +32,24 @@ TEST(filesystem_test, normalize) helpers::normalize_path(fs::path("/first////second/../third/././.")).string()); } +TEST(filesystem_test, test_check_relative) +{ + ASSERT_TRUE(helpers::check_relative(fs::path(""))); + ASSERT_TRUE(helpers::check_relative(fs::path("."))); + ASSERT_TRUE(helpers::check_relative(fs::path("sth"))); + ASSERT_TRUE(helpers::check_relative(fs::path("sth/sth"))); + ASSERT_TRUE(helpers::check_relative(fs::path("./sth"))); + ASSERT_TRUE(helpers::check_relative(fs::path("./sth/sth"))); + ASSERT_FALSE(helpers::check_relative(fs::path("/"))); + ASSERT_FALSE(helpers::check_relative(fs::path("/sth"))); + ASSERT_FALSE(helpers::check_relative(fs::path("/sth/sth"))); + ASSERT_FALSE(helpers::check_relative(fs::path(".."))); + ASSERT_FALSE(helpers::check_relative(fs::path("../sth"))); + ASSERT_FALSE(helpers::check_relative(fs::path("sth/.."))); + ASSERT_FALSE(helpers::check_relative(fs::path("sth/sth/.."))); + ASSERT_FALSE(helpers::check_relative(fs::path("sth/sth/../sth"))); +} + bound_dirs_type get_default_dirs() { diff --git a/tests/job_config.cpp b/tests/job_config.cpp index 24c9f889..2eb25849 100644 --- a/tests/job_config.cpp +++ b/tests/job_config.cpp @@ -143,6 +143,7 @@ TEST(job_config_test, correct_format) " stdin: 01.in\n" " stdout: 01.out\n" " stderr: 01.err\n" + " working-directory: working\n" " limits:\n" " - hw-group-id: group1\n" " time: 5\n" @@ -198,6 +199,7 @@ TEST(job_config_test, config_data) " stdout: 01.out\n" " stderr: 01.err\n" " chdir: /eval\n" + " working-directory: working\n" " limits:\n" " - hw-group-id: group1\n" " time: 5\n" @@ -253,6 +255,7 @@ TEST(job_config_test, config_data) ASSERT_EQ(task2->sandbox->std_output, "01.out"); ASSERT_EQ(task2->sandbox->std_error, "01.err"); ASSERT_EQ(task2->sandbox->chdir, "/eval"); + ASSERT_EQ(task2->sandbox->working_directory, "working"); ASSERT_EQ(task2->sandbox->loaded_limits.size(), 2u); EXPECT_NO_THROW(task2->sandbox->loaded_limits.at("group1"));