From f23a77156f22895df9bcadbabe8d55fd1dbe18ab Mon Sep 17 00:00:00 2001 From: avogar Date: Thu, 22 Sep 2022 13:52:39 +0000 Subject: [PATCH] Check file path for path traversal attacks in errors logger for input formats --- .../Formats/InputFormatErrorsLogger.cpp | 24 +++++++++++++++---- ...2453_check_path_in_errors_logger.reference | 0 .../02453_check_path_in_errors_logger.sql | 3 +++ 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 tests/queries/0_stateless/02453_check_path_in_errors_logger.reference create mode 100644 tests/queries/0_stateless/02453_check_path_in_errors_logger.sql diff --git a/src/Processors/Formats/InputFormatErrorsLogger.cpp b/src/Processors/Formats/InputFormatErrorsLogger.cpp index e6f8cdd43ee..88d27abf610 100644 --- a/src/Processors/Formats/InputFormatErrorsLogger.cpp +++ b/src/Processors/Formats/InputFormatErrorsLogger.cpp @@ -1,15 +1,20 @@ #include +#include #include #include #include #include -#include -#include +#include namespace DB { +namespace ErrorCodes +{ + extern const int DATABASE_ACCESS_DENIED; +} + namespace { const String DEFAULT_OUTPUT_FORMAT = "CSV"; @@ -26,8 +31,19 @@ InputFormatErrorsLogger::InputFormatErrorsLogger(const ContextPtr & context) database = context->getInsertionTable().getDatabaseName(); String path_in_setting = context->getSettingsRef().input_format_record_errors_file_path; - errors_file_path = context->getApplicationType() == Context::ApplicationType::SERVER ? context->getUserFilesPath() + path_in_setting - : path_in_setting; + + if (context->getApplicationType() == Context::ApplicationType::SERVER) + { + auto user_files_path = context->getUserFilesPath(); + errors_file_path = fs::path(user_files_path) / path_in_setting; + if (!fileOrSymlinkPathStartsWith(errors_file_path, user_files_path)) + throw Exception(ErrorCodes::DATABASE_ACCESS_DENIED, "Cannot log errors in path `{}`, because it is not inside `{}`", errors_file_path, user_files_path); + } + else + { + errors_file_path = path_in_setting; + } + while (fs::exists(errors_file_path)) { errors_file_path += "_new"; diff --git a/tests/queries/0_stateless/02453_check_path_in_errors_logger.reference b/tests/queries/0_stateless/02453_check_path_in_errors_logger.reference new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/queries/0_stateless/02453_check_path_in_errors_logger.sql b/tests/queries/0_stateless/02453_check_path_in_errors_logger.sql new file mode 100644 index 00000000000..0fab5c02719 --- /dev/null +++ b/tests/queries/0_stateless/02453_check_path_in_errors_logger.sql @@ -0,0 +1,3 @@ +insert into function file(02453_data.jsonl, TSV) select 1 settings engine_file_truncate_on_insert=1; +select * from file(data.jsonl, auto, 'x UInt32') settings input_format_allow_errors_num=1, input_format_record_errors_file_path='../error_file'; -- {serverError DATABASE_ACCESS_DENIED} +