已合并
fix: harden path validation in reselect_static_kernel_with_path #40497
rich创建于 7月8日
fix: harden path validation in reselect_static_kernel_with_path #40497
已合并
共 4 个文件变更+40-24
| @@ -1,13 +1,10 @@ | |||
| 1 | -import os | ||
| 2 | -import subprocess | ||
| 3 | -import datetime | ||
| 4 | -from pathlib import Path | ||
| 5 | import stat | 1 | import stat |
| 2 | +import unittest | ||
| 3 | +from pathlib import Path | ||
| 4 | + | ||
| 6 | import torch_npu | 5 | import torch_npu |
| 7 | -from torch_npu._inductor.config import log | 6 | +from torch_npu._inductor.npu_static_kernel import StaticKernelCompiler, safe_resolve_output_dir |
| 8 | -from torch_npu._inductor.npu_static_kernel import StaticKernelCompiler | ||
| 9 | from torch_npu.testing.testcase import TestCase, run_tests | 7 | from torch_npu.testing.testcase import TestCase, run_tests |
| 10 | -from torch_npu._inductor.npu_static_kernel import safe_resolve_output_dir | ||
| 11 | 8 | ||
| 12 | 9 | ||
| 13 | class TestNpuStaticKernel(TestCase): | 10 | class TestNpuStaticKernel(TestCase): |
| @@ -63,9 +60,9 @@ class TestNpuStaticKernel(TestCase): | |||
| 63 | safe_resolve_output_dir(build_path) | 60 | safe_resolve_output_dir(build_path) |
| 64 | 61 | ||
| 65 | def test_uninstall_static_kernel_no_path(self): | 62 | def test_uninstall_static_kernel_no_path(self): |
| 66 | - from torch_npu._inductor.npu_static_kernel import _uninstall_path, uninstall_static_kernel | 63 | + from torch_npu._inductor.npu_static_kernel import uninstall_static_kernel |
| 67 | - _uninstall_path = None | 64 | + with unittest.mock.patch("torch_npu._inductor.npu_static_kernel._uninstall_path", None): |
| 68 | - uninstall_static_kernel() | 65 | + uninstall_static_kernel() |
| 69 | 66 | ||
| 70 | def test_static_kernel_compiler_context_manager(self): | 67 | def test_static_kernel_compiler_context_manager(self): |
| 71 | with StaticKernelCompiler() as compiler: | 68 | with StaticKernelCompiler() as compiler: |
| @@ -80,7 +77,6 @@ class TestNpuStaticKernel(TestCase): | |||
| 80 | 77 | ||
| 81 | def test_safe_resolve_output_dir_absolute_path(self): | 78 | def test_safe_resolve_output_dir_absolute_path(self): |
| 82 | import tempfile | 79 | import tempfile |
| 83 | - import shutil | ||
| 84 | with tempfile.TemporaryDirectory() as tmpdir: | 80 | with tempfile.TemporaryDirectory() as tmpdir: |
| 85 | abs_dir = Path(tmpdir) / "test_build" | 81 | abs_dir = Path(tmpdir) / "test_build" |
| 86 | abs_dir.mkdir() | 82 | abs_dir.mkdir() |
| @@ -88,6 +84,23 @@ class TestNpuStaticKernel(TestCase): | |||
| 88 | self.assertTrue(result.exists()) | 84 | self.assertTrue(result.exists()) |
| 89 | self.assertIn("kernel_aot_optimization_build_outputs", str(result)) | 85 | self.assertIn("kernel_aot_optimization_build_outputs", str(result)) |
| 90 | 86 | ||
| 87 | + def test_reselect_static_kernel_with_path_not_string(self): | ||
| 88 | + with self.assertRaisesRegex(RuntimeError, "path must be a string"): | ||
| 89 | + torch_npu._C._aclnn_reselect_static_kernel_with_path(123) | ||
| 90 | + | ||
| 91 | + def test_reselect_static_kernel_with_path_null_byte(self): | ||
| 92 | + with self.assertRaisesRegex(RuntimeError, "null byte"): | ||
| 93 | + torch_npu._C._aclnn_reselect_static_kernel_with_path("test\x00dir") | ||
| 94 | + | ||
| 95 | + def test_reselect_static_kernel_with_path_non_existent(self): | ||
| 96 | + with self.assertRaisesRegex(RuntimeError, "failed to resolve path"): | ||
| 97 | + torch_npu._C._aclnn_reselect_static_kernel_with_path("/nonexistent/path") | ||
| 98 | + | ||
| 99 | + def test_reselect_static_kernel_with_path_is_file(self): | ||
| 100 | + import tempfile | ||
| 101 | + with tempfile.NamedTemporaryFile() as f: | ||
| 102 | + with self.assertRaisesRegex(RuntimeError, "must be a directory"): | ||
| 103 | + torch_npu._C._aclnn_reselect_static_kernel_with_path(f.name) | ||
| 91 | 104 | ||
| 92 | if __name__ == "__main__": | 105 | if __name__ == "__main__": |
| 93 | run_tests() | 106 | run_tests() |
| @@ -47,10 +47,10 @@ aclnnStatus ReselectStaticKernelWithPath(const std::string &path) | |||
| 47 | if (aclnnReselectStaticKernelWithPathFunc == nullptr) { | 47 | if (aclnnReselectStaticKernelWithPathFunc == nullptr) { |
| 48 | aclnnReselectStaticKernelWithPathFunc = | 48 | aclnnReselectStaticKernelWithPathFunc = |
| 49 | (AclnnApiFunc)TORCH_NPU_GET_FUNC(aclnnReselectStaticKernelWithPath); | 49 | (AclnnApiFunc)TORCH_NPU_GET_FUNC(aclnnReselectStaticKernelWithPath); |
| 50 | + TORCH_CHECK(aclnnReselectStaticKernelWithPathFunc, | ||
| 51 | + "Failed to find function ", "aclnnReselectStaticKernelWithPath", | ||
| 52 | + PTA_ERROR(ErrCode::NOT_FOUND)); | ||
| 50 | } | 53 | } |
| 51 | - TORCH_CHECK(aclnnReselectStaticKernelWithPathFunc, | ||
| 52 | - "Failed to find function ", "aclnnReselectStaticKernelWithPath", | ||
| 53 | - PTA_ERROR(ErrCode::NOT_FOUND)); | ||
| 54 | auto ret = aclnnReselectStaticKernelWithPathFunc(path.c_str()); | 54 | auto ret = aclnnReselectStaticKernelWithPathFunc(path.c_str()); |
| 55 | return ret; | 55 | return ret; |
| 56 | } | 56 | } |
| @@ -18,8 +18,7 @@ bool IsExistAclnnSilentCheck(); | |||
| 18 | aclnnStatus ReselectStaticKernel(); | 18 | aclnnStatus ReselectStaticKernel(); |
| 19 | 19 | ||
| 20 | /** | 20 | /** |
| 21 | - This Api is used to reselect static kernel with a specified path, | 21 | + This Api is used to reselect static kernel with a specified path. |
| 22 | - it need to be called once at process. | ||
| 23 | */ | 22 | */ |
| 24 | aclnnStatus ReselectStaticKernelWithPath(const std::string &path); | 23 | aclnnStatus ReselectStaticKernelWithPath(const std::string &path); |
| 25 | 24 | ||
| @@ -1,5 +1,7 @@ | |||
| 1 | 1 | ||
| 2 | + | ||
| 2 | 3 | ||
| 4 | + | ||
| 3 | 5 | ||
| 4 | 6 | ||
| 5 | 7 | ||
| @@ -2093,13 +2095,15 @@ PyObject* THNPModule_aclnn_reselect_static_kernel_with_path( | |||
| 2093 | TORCH_CHECK(path.find('\0') == std::string::npos, | 2095 | TORCH_CHECK(path.find('\0') == std::string::npos, |
| 2094 | "path must not contain null byte", | 2096 | "path must not contain null byte", |
| 2095 | PTA_ERROR(ErrCode::PARAM)); | 2097 | PTA_ERROR(ErrCode::PARAM)); |
| 2096 | - struct stat st; | 2098 | + char abs_path[PATH_MAX] = {'\0'}; |
| 2097 | - TORCH_CHECK(stat(path.c_str(), &st) == 0, | 2099 | + TORCH_CHECK(realpath(path.c_str(), abs_path) != nullptr, |
| 2098 | - "path does not exist: ", path, | 2100 | + "failed to resolve path: ", path, |
| 2099 | PTA_ERROR(ErrCode::NOT_FOUND)); | 2101 | PTA_ERROR(ErrCode::NOT_FOUND)); |
| 2100 | - TORCH_CHECK(S_ISDIR(st.st_mode), | 2102 | + struct stat st; |
| 2101 | - "path must be a directory: ", path, | 2103 | + TORCH_CHECK(stat(abs_path, &st) == 0 && S_ISDIR(st.st_mode), |
| 2104 | + "path must be a directory: ", abs_path, | ||
| 2102 | PTA_ERROR(ErrCode::PARAM)); | 2105 | PTA_ERROR(ErrCode::PARAM)); |
| 2106 | + std::string resolved_path(abs_path); | ||
| 2103 | 2107 | ||
| 2104 | NPUStatus ret = c10_npu::emptyAllNPUStream(); | 2108 | NPUStatus ret = c10_npu::emptyAllNPUStream(); |
| 2105 | TORCH_CHECK( | 2109 | TORCH_CHECK( |
| @@ -2111,8 +2115,8 @@ PyObject* THNPModule_aclnn_reselect_static_kernel_with_path( | |||
| 2111 | static const auto task_queue_enable = | 2115 | static const auto task_queue_enable = |
| 2112 | c10_npu::option::OptionsManager::GetTaskQueueEnable(); | 2116 | c10_npu::option::OptionsManager::GetTaskQueueEnable(); |
| 2113 | if (task_queue_enable == 2) { | 2117 | if (task_queue_enable == 2) { |
| 2114 | - auto acl_call = [path]() -> int { | 2118 | + auto acl_call = [resolved_path]() -> int { |
| 2115 | - return c10_npu::opapi::ReselectStaticKernelWithPath(path); | 2119 | + return c10_npu::opapi::ReselectStaticKernelWithPath(resolved_path); |
| 2116 | }; | 2120 | }; |
| 2117 | at_npu::native::OpCommand::RunOpApiV2("reselect_static_kernel_with_path", acl_call); | 2121 | at_npu::native::OpCommand::RunOpApiV2("reselect_static_kernel_with_path", acl_call); |
| 2118 | NPUStatus ret = c10_npu::emptyAllNPUStream(); | 2122 | NPUStatus ret = c10_npu::emptyAllNPUStream(); |
| @@ -2122,7 +2126,7 @@ PyObject* THNPModule_aclnn_reselect_static_kernel_with_path( | |||
| 2122 | ret, | 2126 | ret, |
| 2123 | PTA_ERROR(ErrCode::INTERNAL)); | 2127 | PTA_ERROR(ErrCode::INTERNAL)); |
| 2124 | } else { | 2128 | } else { |
| 2125 | - NPU_CHECK_ERROR(c10_npu::opapi::ReselectStaticKernelWithPath(path)); | 2129 | + NPU_CHECK_ERROR(c10_npu::opapi::ReselectStaticKernelWithPath(resolved_path)); |
| 2126 | } | 2130 | } |
| 2127 | 2131 | ||
| 2128 | Py_RETURN_NONE; | 2132 | Py_RETURN_NONE; |