[OpenVINO EP] Validate that EPContext binary path is within model con…#28605
[OpenVINO EP] Validate that EPContext binary path is within model con…#28605adrianlizarraga wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds validation for the OpenVINO EPContext external-blob path (ep_cache_context) to reduce path traversal risk when loading EPContext artifacts.
Changes:
- Introduces filesystem-based helpers to classify
ep_cache_contextas absolute vs. relative. - Adds
ORT_ENFORCEguards to reject absolute paths and paths containing..before resolving blob/context file locations. - Applies these validations in both EPContext blob reading (
GetModelBlobStream) and shared context initialization (Initialize).
Comments suppressed due to low confidence (2)
onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc:142
- These checks ensure
ep_cache_contextis not absolute and doesn't contain "..", but they still allow directory escape if the combined path resolves via symlinks, and they don't guard the case whereblob_filepath(base model/context path) is empty (then the lookup becomes relative to the process CWD). Consider computing a canonical/weakly_canonical combined path and enforcing it is within the canonical base directory, and ORT_ENFORCE that the base path is non-empty before joining.
// ep_cache_context must be a relative path within the context model directory.
ORT_ENFORCE(!IsAbsolutePath(ep_cache_context),
"ep_cache_context must be a relative path, but got absolute path: ", ep_cache_context);
ORT_ENFORCE(!IsRelativePathToParentPath(ep_cache_context),
"ep_cache_context must not contain '..'; it cannot point outside the model directory.");
blob_filepath = blob_filepath.parent_path() / ep_cache_context;
ORT_ENFORCE(std::filesystem::exists(blob_filepath), "Blob file not found: ", blob_filepath.string());
onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc:275
- Same path validation issue as in
GetModelBlobStream: rejecting absolute paths and ".." is not sufficient to guarantee the resolvedep_context_pathstays within the model directory (symlink escape, andGetOutputModelPath()can be empty so the base directory becomes empty). Consider enforcing a non-empty base path and verifying the canonicalized resolved path has the base directory as its prefix.
// ep_cache_context must be a relative path within the context model directory.
ORT_ENFORCE(!IsAbsolutePath(ep_cache_context),
"ep_cache_context must be a relative path, but got absolute path: ", ep_cache_context);
ORT_ENFORCE(!IsRelativePathToParentPath(ep_cache_context),
"ep_cache_context must not contain '..'; it cannot point outside the model directory.");
std::filesystem::path ep_context_path = session_context.GetOutputModelPath().parent_path() / ep_cache_context;
if (ep_context_path.extension() != ".xml") {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
onnxruntime/core/providers/openvino/onnx_ctx_model_helper.cc:145
- Before calling IsModelStreamXML, please validate that ep_cache_context is non-empty and that the resolved path is a regular file and readable. std::filesystem::exists() returns true for directories too, and std::ifstream can fail to open (permissions, directory path), which currently results in a less actionable failure inside IsModelStreamXML (tellg/seekg/size checks).
ORT_ENFORCE(!IsRelativePathToParentPath(ep_cache_context),
"ep_cache_context must not contain '..'; it cannot point outside the model directory.");
blob_filepath = blob_filepath.parent_path() / ep_cache_context;
ORT_ENFORCE(std::filesystem::exists(blob_filepath), "Blob file not found: ", blob_filepath.string());
result.reset((std::istream*)new std::ifstream(blob_filepath, std::ios_base::binary | std::ios_base::in));
}
| // ep_cache_context must be a relative path within the context model directory. | ||
| ORT_ENFORCE(!IsAbsolutePath(ep_cache_context), | ||
| "ep_cache_context must be a relative path, but got absolute path: ", ep_cache_context); | ||
| ORT_ENFORCE(!IsRelativePathToParentPath(ep_cache_context), | ||
| "ep_cache_context must not contain '..'; it cannot point outside the model directory."); | ||
| blob_filepath = blob_filepath.parent_path() / ep_cache_context; | ||
| ORT_ENFORCE(std::filesystem::exists(blob_filepath), "Blob file not found: ", blob_filepath.string()); |
There was a problem hiding this comment.
Using weakly_canonical
| // ep_cache_context must be a relative path within the context model directory. | ||
| ORT_ENFORCE(!IsAbsolutePath(ep_cache_context), | ||
| "ep_cache_context must be a relative path, but got absolute path: ", ep_cache_context); | ||
| ORT_ENFORCE(!IsRelativePathToParentPath(ep_cache_context), | ||
| "ep_cache_context must not contain '..'; it cannot point outside the model directory."); | ||
| std::filesystem::path ep_context_path = session_context.GetOutputModelPath().parent_path() / ep_cache_context; | ||
| if (ep_context_path.extension() != ".xml") { |
There was a problem hiding this comment.
Now using weakly_canonical
| bool IsRelativePathToParentPath(const std::string& path_string) { | ||
| auto normalized = std::filesystem::path(path_string).lexically_normal(); | ||
| for (const auto& component : normalized) { | ||
| if (component == "..") { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } |
There was a problem hiding this comment.
Now using weakly_canonical
…text directory
Description
Motivation and Context