public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/onnx] test-1.21.0: Backport of fixes for CVE-2024-27318 and CVE-2024-27319
@ 2026-06-08 15:18 Alejandro Alvarez Ayllon
0 siblings, 0 replies; only message in thread
From: Alejandro Alvarez Ayllon @ 2026-06-08 15:18 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/onnx
Branch : test-1.21.0
Commit : 0bc03015f99f80a102f41c3720e2e65295c91683
Author : Alejandro Alvarez Ayllon <a.alvarezayllon@gmail.com>
Date : 2024-02-24T16:18:04+01:00
Stats : +493/-1 in 4 file(s)
URL : https://src.fedoraproject.org/rpms/onnx/c/0bc03015f99f80a102f41c3720e2e65295c91683?branch=test-1.21.0
Log:
Backport of fixes for CVE-2024-27318 and CVE-2024-27319
---
diff --git a/0005-Fix-path-sanitization-bypass-leading-to-arbitrary-re.patch b/0005-Fix-path-sanitization-bypass-leading-to-arbitrary-re.patch
new file mode 100644
index 0000000..67d71bb
--- /dev/null
+++ b/0005-Fix-path-sanitization-bypass-leading-to-arbitrary-re.patch
@@ -0,0 +1,380 @@
+From da2c24b4a9ae802efe8768962308c784cda871e2 Mon Sep 17 00:00:00 2001
+From: liqun Fu <liqfu@microsoft.com>
+Date: Mon, 19 Feb 2024 11:12:40 -0800
+Subject: [PATCH 5/6] Fix path sanitization bypass leading to arbitrary read
+ (#5917)
+
+Signed-off-by: liqunfu <liqun.fu@microsoft.com>
+Signed-off-by: liqun Fu <liqun.fu@microsoft.com>
+Co-authored-by: Justin Chu <justinchuby@users.noreply.github.com>
+(cherry picked from commit 66b7fb630903fdcf3e83b6b6d56d82e904264a20)
+---
+ onnx/checker.cc | 168 +++++++++++++++++---------------
+ onnx/checker.h | 5 +
+ onnx/common/path.h | 15 ++-
+ onnx/cpp2py_export.cc | 2 +
+ onnx/external_data_helper.py | 15 +--
+ onnx/test/test_external_data.py | 49 ++++++++++
+ 6 files changed, 161 insertions(+), 93 deletions(-)
+
+diff --git a/onnx/checker.cc b/onnx/checker.cc
+index 37d6abd3..38e544be 100644
+--- a/onnx/checker.cc
++++ b/onnx/checker.cc
+@@ -4,7 +4,6 @@
+
+ #include "onnx/checker.h"
+ #include "onnx/common/file_utils.h"
+-#include "onnx/common/path.h"
+ #include "onnx/defs/schema.h"
+ #include "onnx/defs/tensor_proto_util.h"
+ #include "onnx/proto_utils.h"
+@@ -129,85 +128,7 @@ void check_tensor(const TensorProto& tensor, const CheckerContext& ctx) {
+ for (const StringStringEntryProto& entry : tensor.external_data()) {
+ if (entry.has_key() && entry.has_value() && entry.key() == "location") {
+ has_location = true;
+-#ifdef _WIN32
+- auto file_path = std::filesystem::path(utf8str_to_wstring(entry.value()));
+- if (file_path.is_absolute()) {
+- fail_check(
+- "Location of external TensorProto ( tensor name: ",
+- tensor.name(),
+- ") should be a relative path, but it is an absolute path: ",
+- entry.value());
+- }
+- auto relative_path = file_path.lexically_normal().make_preferred().wstring();
+- // Check that normalized relative path contains ".." on Windows.
+- if (relative_path.find(L"..", 0) != std::string::npos) {
+- fail_check(
+- "Data of TensorProto ( tensor name: ",
+- tensor.name(),
+- ") should be file inside the ",
+- ctx.get_model_dir(),
+- ", but the '",
+- entry.value(),
+- "' points outside the directory");
+- }
+- std::wstring data_path = path_join(utf8str_to_wstring(ctx.get_model_dir()), relative_path);
+- struct _stat64 buff;
+- if (_wstat64(data_path.c_str(), &buff) != 0) {
+- fail_check(
+- "Data of TensorProto ( tensor name: ",
+- tensor.name(),
+- ") should be stored in ",
+- entry.value(),
+- ", but it doesn't exist or is not accessible.");
+- }
+-#else // POSIX
+- if (entry.value().empty()) {
+- fail_check("Location of external TensorProto ( tensor name: ", tensor.name(), ") should not be empty.");
+- } else if (entry.value()[0] == '/') {
+- fail_check(
+- "Location of external TensorProto ( tensor name: ",
+- tensor.name(),
+- ") should be a relative path, but it is an absolute path: ",
+- entry.value());
+- }
+- std::string relative_path = clean_relative_path(entry.value());
+- // Check that normalized relative path contains ".." on POSIX
+- if (relative_path.find("..", 0) != std::string::npos) {
+- fail_check(
+- "Data of TensorProto ( tensor name: ",
+- tensor.name(),
+- ") should be file inside the ",
+- ctx.get_model_dir(),
+- ", but the '",
+- entry.value(),
+- "' points outside the directory");
+- }
+- std::string data_path = path_join(ctx.get_model_dir(), relative_path);
+- // use stat64 to check whether the file exists
+-#if defined(__APPLE__) || defined(__wasm__)
+- struct stat buffer; // APPLE does not have stat64
+- if (stat((data_path).c_str(), &buffer) != 0) {
+-#else
+- struct stat64 buffer; // All POSIX except APPLE have stat64
+- if (stat64((data_path).c_str(), &buffer) != 0) {
+-#endif
+- fail_check(
+- "Data of TensorProto ( tensor name: ",
+- tensor.name(),
+- ") should be stored in ",
+- data_path,
+- ", but it doesn't exist or is not accessible.");
+- }
+- // Do not allow symlinks or directories.
+- if (!S_ISREG(buffer.st_mode)) {
+- fail_check(
+- "Data of TensorProto ( tensor name: ",
+- tensor.name(),
+- ") should be stored in ",
+- data_path,
+- ", but it is not regular file.");
+- }
+-#endif
++ resolve_external_data_location(ctx.get_model_dir(), entry.value(), tensor.name());
+ }
+ }
+ if (!has_location) {
+@@ -1045,6 +966,93 @@ void check_model(const ModelProto& model, bool full_check) {
+ }
+ }
+
++std::string resolve_external_data_location(
++ const std::string& base_dir,
++ const std::string& location,
++ const std::string& tensor_name) {
++#ifdef _WIN32
++ auto file_path = std::filesystem::path(utf8str_to_wstring(location));
++ if (file_path.is_absolute()) {
++ fail_check(
++ "Location of external TensorProto ( tensor name: ",
++ tensor_name,
++ ") should be a relative path, but it is an absolute path: ",
++ location);
++ }
++ auto relative_path = file_path.lexically_normal().make_preferred().wstring();
++ // Check that normalized relative path contains ".." on Windows.
++ if (relative_path.find(L"..", 0) != std::string::npos) {
++ fail_check(
++ "Data of TensorProto ( tensor name: ",
++ tensor_name,
++ ") should be file inside the ",
++ base_dir,
++ ", but the '",
++ location,
++ "' points outside the directory");
++ }
++ std::wstring data_path = path_join(utf8str_to_wstring(base_dir), relative_path);
++ struct _stat64 buff;
++ if (data_path.empty() || (data_path[0] != '#' && _wstat64(data_path.c_str(), &buff) != 0)) {
++ fail_check(
++ "Data of TensorProto ( tensor name: ",
++ tensor_name,
++ ") should be stored in ",
++ location,
++ ", but it doesn't exist or is not accessible.");
++ }
++ return wstring_to_utf8str(data_path);
++#else // POSIX
++ if (location.empty()) {
++ fail_check("Location of external TensorProto ( tensor name: ", tensor_name, ") should not be empty.");
++ } else if (location[0] == '/') {
++ fail_check(
++ "Location of external TensorProto ( tensor name: ",
++ tensor_name,
++ ") should be a relative path, but it is an absolute path: ",
++ location);
++ }
++ std::string relative_path = clean_relative_path(location);
++ // Check that normalized relative path contains ".." on POSIX
++ if (relative_path.find("..", 0) != std::string::npos) {
++ fail_check(
++ "Data of TensorProto ( tensor name: ",
++ tensor_name,
++ ") should be file inside the ",
++ base_dir,
++ ", but the '",
++ location,
++ "' points outside the directory");
++ }
++ std::string data_path = path_join(base_dir, relative_path);
++ // use stat64 to check whether the file exists
++#if defined(__APPLE__) || defined(__wasm__) || !defined(__GLIBC__)
++ struct stat buffer; // APPLE, wasm and non-glic stdlibs do not have stat64
++ if (data_path.empty() || (data_path[0] != '#' && stat((data_path).c_str(), &buffer) != 0)) {
++#else
++ struct stat64 buffer; // All POSIX under glibc except APPLE and wasm have stat64
++ if (data_path.empty() || (data_path[0] != '#' && stat64((data_path).c_str(), &buffer) != 0)) {
++#endif
++ fail_check(
++ "Data of TensorProto ( tensor name: ",
++ tensor_name,
++ ") should be stored in ",
++ data_path,
++ ", but it doesn't exist or is not accessible.");
++ }
++ // Do not allow symlinks or directories.
++ if (data_path.empty() || (data_path[0] != '#' && !S_ISREG(buffer.st_mode))) {
++ fail_check(
++ "Data of TensorProto ( tensor name: ",
++ tensor_name,
++ ") should be stored in ",
++ data_path,
++ ", but it is not regular file.");
++ }
++ return data_path;
++#endif
++}
++
+ std::set<std::string> experimental_ops = {
+ "ATen",
+ "Affine",
+diff --git a/onnx/checker.h b/onnx/checker.h
+index 54fe19aa..6f1d47b2 100644
+--- a/onnx/checker.h
++++ b/onnx/checker.h
+@@ -149,6 +149,11 @@ void check_model_local_functions(
+ void check_model(const ModelProto& model, bool full_check = false);
+ void check_model(const std::string& model_path, bool full_check = false);
+
++std::string resolve_external_data_location(
++ const std::string& base_dir,
++ const std::string& location,
++ const std::string& tensor_name);
++
+ bool check_is_experimental_op(const NodeProto& node);
+
+ } // namespace checker
+diff --git a/onnx/common/path.h b/onnx/common/path.h
+index d06eef90..fc692152 100644
+--- a/onnx/common/path.h
++++ b/onnx/common/path.h
+@@ -29,11 +29,22 @@ inline std::wstring utf8str_to_wstring(const std::string& utf8str) {
+ if (utf8str.size() > INT_MAX) {
+ fail_check("utf8str_to_wstring: string is too long for converting to wstring.");
+ }
+- int size_required = MultiByteToWideChar(CP_UTF8, 0, utf8str.c_str(), (int)utf8str.size(), NULL, 0);
++ int size_required = MultiByteToWideChar(CP_UTF8, 0, utf8str.c_str(), static_cast<int>(utf8str.size()), NULL, 0);
+ std::wstring ws_str(size_required, 0);
+- MultiByteToWideChar(CP_UTF8, 0, utf8str.c_str(), (int)utf8str.size(), &ws_str[0], size_required);
++ MultiByteToWideChar(CP_UTF8, 0, utf8str.c_str(), static_cast<int>(utf8str.size()), &ws_str[0], size_required);
+ return ws_str;
+ }
++inline std::string wstring_to_utf8str(const std::wstring& ws_str) {
++ if (ws_str.size() > INT_MAX) {
++ fail_check("wstring_to_utf8str: string is too long for converting to UTF-8.");
++ }
++ int size_required =
++ WideCharToMultiByte(CP_UTF8, 0, ws_str.c_str(), static_cast<int>(ws_str.size()), NULL, 0, NULL, NULL);
++ std::string utf8str(size_required, 0);
++ WideCharToMultiByte(
++ CP_UTF8, 0, ws_str.c_str(), static_cast<int>(ws_str.size()), &utf8str[0], size_required, NULL, NULL);
++ return utf8str;
++}
+
+ #else
+ std::string path_join(const std::string& origin, const std::string& append);
+diff --git a/onnx/cpp2py_export.cc b/onnx/cpp2py_export.cc
+index 656f8fa7..dd53b197 100644
+--- a/onnx/cpp2py_export.cc
++++ b/onnx/cpp2py_export.cc
+@@ -538,6 +538,8 @@ PYBIND11_MODULE(onnx_cpp2py_export, onnx_cpp2py_export) {
+ "path"_a,
+ "full_check"_a = false);
+
++ checker.def("_resolve_external_data_location", &checker::resolve_external_data_location);
++
+ // Submodule `version_converter`
+ auto version_converter = onnx_cpp2py_export.def_submodule("version_converter");
+ version_converter.doc() = "VersionConverter submodule";
+diff --git a/onnx/external_data_helper.py b/onnx/external_data_helper.py
+index cfb97d06..992c324b 100644
+--- a/onnx/external_data_helper.py
++++ b/onnx/external_data_helper.py
+@@ -8,6 +8,7 @@ import uuid
+ from itertools import chain
+ from typing import Callable, Iterable, Optional
+
++import onnx.onnx_cpp2py_export.checker as c_checker
+ from onnx.onnx_pb import AttributeProto, GraphProto, ModelProto, TensorProto
+
+
+@@ -39,9 +40,9 @@ def load_external_data_for_tensor(tensor: TensorProto, base_dir: str) -> None:
+ base_dir: directory that contains the external data.
+ """
+ info = ExternalDataInfo(tensor)
+- file_location = _sanitize_path(info.location)
+- external_data_file_path = os.path.join(base_dir, file_location)
+-
++ external_data_file_path = c_checker._resolve_external_data_location( # type: ignore[attr-defined]
++ base_dir, info.location, tensor.name
++ )
+ with open(external_data_file_path, "rb") as data_file:
+ if info.offset:
+ data_file.seek(info.offset)
+@@ -254,14 +255,6 @@ def _get_attribute_tensors(onnx_model_proto: ModelProto) -> Iterable[TensorProto
+ yield from _get_attribute_tensors_from_graph(onnx_model_proto.graph)
+
+
+-def _sanitize_path(path: str) -> str:
+- """Remove path components which would allow traversing up a directory tree from a base path.
+-
+- Note: This method is currently very basic and should be expanded.
+- """
+- return path.lstrip("/.")
+-
+-
+ def _is_valid_filename(filename: str) -> bool:
+ """Utility to check whether the provided filename is valid."""
+ exp = re.compile('^[^<>:;,?"*|/]+$')
+diff --git a/onnx/test/test_external_data.py b/onnx/test/test_external_data.py
+index b4303b4a..c7d03d78 100644
+--- a/onnx/test/test_external_data.py
++++ b/onnx/test/test_external_data.py
+@@ -1,6 +1,9 @@
+ # Copyright (c) ONNX Project Contributors
+
+ # SPDX-License-Identifier: Apache-2.0
++from __future__ import annotations
++
++import itertools
+ import os
+ import shutil
+ import tempfile
+@@ -186,6 +189,52 @@ class TestLoadExternalDataSingleFile(TestLoadExternalDataBase):
+ attribute_tensor = new_model.graph.node[0].attribute[0].t
+ self.assertTrue(np.allclose(to_array(attribute_tensor), self.attribute_value))
+
++ @parameterized.parameterized.expand(itertools.product((True, False), (True, False)))
++ def test_save_external_invalid_single_file_data_and_check(
++ self, use_absolute_path: bool, use_model_path: bool
++ ) -> None:
++ model = onnx.load_model(self.model_filename, self.serialization_format)
++
++ model_dir = os.path.join(self.temp_dir, "save_copy")
++ os.mkdir(model_dir)
++
++ traversal_external_data_dir = os.path.join(
++ self.temp_dir, "invlid_external_data"
++ )
++ os.mkdir(traversal_external_data_dir)
++
++ if use_absolute_path:
++ traversal_external_data_location = os.path.join(
++ traversal_external_data_dir, "tensors.bin"
++ )
++ else:
++ traversal_external_data_location = "../invlid_external_data/tensors.bin"
++
++ external_data_dir = os.path.join(self.temp_dir, "external_data")
++ os.mkdir(external_data_dir)
++ new_model_filepath = os.path.join(model_dir, "model.onnx")
++
++ def convert_model_to_external_data_no_check(model: ModelProto, location: str):
++ for tensor in model.graph.initializer:
++ if tensor.HasField("raw_data"):
++ set_external_data(tensor, location)
++
++ convert_model_to_external_data_no_check(
++ model,
++ location=traversal_external_data_location,
++ )
++
++ onnx.save_model(model, new_model_filepath, self.serialization_format)
++ if use_model_path:
++ with self.assertRaises(onnx.checker.ValidationError):
++ _ = onnx.load_model(new_model_filepath, self.serialization_format)
++ else:
++ onnx_model = onnx.load_model(
++ new_model_filepath, self.serialization_format, load_external_data=False
++ )
++ with self.assertRaises(onnx.checker.ValidationError):
++ load_external_data_for_model(onnx_model, external_data_dir)
++
+
+ class TestSaveAllTensorsAsExternalData(TestLoadExternalDataBase):
+ def setUp(self) -> None:
+--
+2.43.0
+
diff --git a/0006-Fix-Out-of-bounds-read-due-to-lack-of-string-termina.patch b/0006-Fix-Out-of-bounds-read-due-to-lack-of-string-termina.patch
new file mode 100644
index 0000000..a7821e7
--- /dev/null
+++ b/0006-Fix-Out-of-bounds-read-due-to-lack-of-string-termina.patch
@@ -0,0 +1,54 @@
+From 69502bca61dafaa40b4315ea1cb03db96ae55304 Mon Sep 17 00:00:00 2001
+From: liqun Fu <liqfu@microsoft.com>
+Date: Fri, 9 Feb 2024 14:45:49 -0800
+Subject: [PATCH 6/6] Fix Out of bounds read due to lack of string termination
+ in assert (#5918)
+
+Signed-off-by: liqunfu <liqun.fu@microsoft.com>
+Co-authored-by: G. Ramalingam <grama@microsoft.com>
+(cherry picked from commit 08a399ba75a805b7813ab8936b91d0e274b08287)
+---
+ onnx/common/assertions.cc | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/onnx/common/assertions.cc b/onnx/common/assertions.cc
+index a21e55da..2099003d 100644
+--- a/onnx/common/assertions.cc
++++ b/onnx/common/assertions.cc
+@@ -8,6 +8,7 @@
+ // Adventurous users should note that the APIs will probably change.
+
+ #include "onnx/common/assertions.h"
++#include <array>
+ #include <cstdarg>
+ #include <cstdio>
+ #include "onnx/common/common.h"
+@@ -15,16 +16,20 @@
+ namespace ONNX_NAMESPACE {
+
+ std::string barf(const char* fmt, ...) {
+- char msg[2048];
++ constexpr size_t buffer_size = 2048;
++ std::array<char, buffer_size> msg{};
+ va_list args;
+
+ va_start(args, fmt);
+- // Although vsnprintf might have vulnerability issue while using format string with overflowed length,
+- // it should be safe here to use fixed length for buffer "msg". No further checking is needed.
+- vsnprintf(msg, 2048, fmt, args);
++
++ // use fixed length for buffer "msg" to avoid buffer overflow
++ vsnprintf(static_cast<char*>(msg.data()), msg.size() - 1, fmt, args);
++
++ // ensure null-terminated string to avoid out of bounds read
++ msg.back() = '\0';
+ va_end(args);
+
+- return std::string(msg);
++ return std::string(msg.data());
+ }
+
+ void throw_assert_error(std::string& msg) {
+--
+2.43.0
+
diff --git a/0007-Fix-test_external_data.patch b/0007-Fix-test_external_data.patch
new file mode 100644
index 0000000..8e11216
--- /dev/null
+++ b/0007-Fix-test_external_data.patch
@@ -0,0 +1,50 @@
+From d2dae07c2bae6714d2496f9eb125314bd20eacda Mon Sep 17 00:00:00 2001
+From: Alejandro Alvarez Ayllon <a.alvarezayllon@gmail.com>
+Date: Sat, 24 Feb 2024 15:15:58 +0100
+Subject: [PATCH 7/7] Fix test_external_data
+
+---
+ onnx/test/test_external_data.py | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/onnx/test/test_external_data.py b/onnx/test/test_external_data.py
+index c7d03d78..c4376159 100644
+--- a/onnx/test/test_external_data.py
++++ b/onnx/test/test_external_data.py
+@@ -5,6 +5,7 @@ from __future__ import annotations
+
+ import itertools
+ import os
++import parameterized
+ import shutil
+ import tempfile
+ import unittest
+@@ -193,7 +194,7 @@ class TestLoadExternalDataSingleFile(TestLoadExternalDataBase):
+ def test_save_external_invalid_single_file_data_and_check(
+ self, use_absolute_path: bool, use_model_path: bool
+ ) -> None:
+- model = onnx.load_model(self.model_filename, self.serialization_format)
++ model = onnx.load_model(self.model_filename)
+
+ model_dir = os.path.join(self.temp_dir, "save_copy")
+ os.mkdir(model_dir)
+@@ -224,13 +225,13 @@ class TestLoadExternalDataSingleFile(TestLoadExternalDataBase):
+ location=traversal_external_data_location,
+ )
+
+- onnx.save_model(model, new_model_filepath, self.serialization_format)
++ onnx.save_model(model, new_model_filepath)
+ if use_model_path:
+ with self.assertRaises(onnx.checker.ValidationError):
+- _ = onnx.load_model(new_model_filepath, self.serialization_format)
++ _ = onnx.load_model(new_model_filepath)
+ else:
+ onnx_model = onnx.load_model(
+- new_model_filepath, self.serialization_format, load_external_data=False
++ new_model_filepath, load_external_data=False
+ )
+ with self.assertRaises(onnx.checker.ValidationError):
+ load_external_data_for_model(onnx_model, external_data_dir)
+--
+2.43.0
+
diff --git a/onnx.spec b/onnx.spec
index 7bf4cc8..61abd0e 100644
--- a/onnx.spec
+++ b/onnx.spec
@@ -1,6 +1,6 @@
Name: onnx
Version: 1.14.1
-Release: 1%{?dist}
+Release: 2%{?dist}
Summary: Open standard for machine learning interoperability
License: Apache-2.0
@@ -16,6 +16,11 @@ Patch2: 0002-Use-system-protobuf-and-require-parameterized.patch
Patch3: 0003-Let-pyproject_wheel-use-binaries-from-cmake_build.patch
# Add fixes for use with onnxruntime
Patch4: 0004-Add-fixes-for-use-with-onnxruntime.patch
+# Backport of fix for CVE-2024-27318
+Patch5: 0005-Fix-path-sanitization-bypass-leading-to-arbitrary-re.patch
+# Backport of fix for CVE-2024-27319
+Patch6: 0006-Fix-Out-of-bounds-read-due-to-lack-of-string-termina.patch
+Patch7: 0007-Fix-test_external_data.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2212096
ExcludeArch: s390x
@@ -110,6 +115,9 @@ export LD_LIBRARY_PATH=%{buildroot}/%{_libdir}
%{_bindir}/check-node
%changelog
+* Sat Feb 24 2024 Alejandro Alvarez Ayllon <a.alvarezayllon@gmail.com> - 1.14.1-2
+- Backport of fixes for CVE-2024-27318 and CVE-2024-27319
+
* Wed Feb 21 2024 Diego Herrera C <dherrera@redhat.com>- 1.14.1-1
- Release 1.14.1
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-06-08 15:18 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-08 15:18 [rpms/onnx] test-1.21.0: Backport of fixes for CVE-2024-27318 and CVE-2024-27319 Alejandro Alvarez Ayllon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox