diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9806b953b..89ef1a9b9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,7 +65,7 @@ endif() # TRITON_ENABLE_GPU # Minimum of 1.78 required for use of boost::span. This can eventually be # relaxed and replaced with std::span in C++20. # -find_package(Boost 1.78 REQUIRED) +find_package(Boost 1.78 REQUIRED COMPONENTS filesystem) message(STATUS "Using Boost ${Boost_VERSION}") # @@ -455,6 +455,7 @@ target_link_libraries( triton-common-table-printer # from repo-common protobuf::libprotobuf ${RE2_LIBRARY} + Boost::filesystem ) if (NOT WIN32) diff --git a/src/model_repository_manager.cc b/src/model_repository_manager.cc index 867365085..4fb5adea5 100644 --- a/src/model_repository_manager.cc +++ b/src/model_repository_manager.cc @@ -28,10 +28,12 @@ #include "model_repository_manager.h" #include +#include #include #include #include #include + #include "backend_model.h" #include "constants.h" #include "ensemble_utils.h" @@ -81,7 +83,8 @@ class LocalizeRepoAgent : public TritonRepoAgent { RETURN_TRITONSERVER_ERROR_IF_ERROR( agent_model->AcquireMutableLocation( TRITONREPOAGENT_ARTIFACT_FILESYSTEM, &temp_dir_cstr)); - const std::string temp_dir = temp_dir_cstr; + const std::string temp_dir = + boost::filesystem::canonical(temp_dir_cstr).string(); const auto& files = *reinterpret_cast*>( agent_model->State()); @@ -109,10 +112,24 @@ class LocalizeRepoAgent : public TritonRepoAgent { .c_str()); } - // Save model file to the instructed directory - // mkdir + // Resolve any relative paths or symlinks, and enforce that target + // directory stays within model directory for security. const std::string file_path = - JoinPath({temp_dir, file->Name().substr(file_prefix.size())}); + boost::filesystem::weakly_canonical( + JoinPath( + {temp_dir, file->Name().substr(file_prefix.size())})) + .string(); + if (file_path.rfind(temp_dir, 0) != 0) { + return TRITONSERVER_ErrorNew( + TRITONSERVER_ERROR_INVALID_ARG, + (std::string("Invalid file parameter '") + file->Name() + + "' with normalized path '" + file_path + + "' must stay within model directory.") + .c_str()); + } + + // Save model override file to the instructed directory using the + // temporary model directory as the basepath. const std::string dir = DirName(file_path); bool dir_exist = false; RETURN_TRITONSERVER_ERROR_IF_ERROR(FileExists(dir, &dir_exist)); @@ -131,7 +148,7 @@ class LocalizeRepoAgent : public TritonRepoAgent { MakeDirectory(dir, true /* recursive */)); } - // write + // Write file contents at specified path RETURN_TRITONSERVER_ERROR_IF_ERROR(WriteBinaryFile( file_path, reinterpret_cast(file->ValuePointer()),