[Misc] Harden AITER_ASM_DIR code-object loading - #4739
Draft
fjankovi wants to merge 1 commit into
Draft
Conversation
AiterAsmKernel resolves its .co from $AITER_ASM_DIR and registers it as a fat binary. In builds that embed their code objects at compile time, that env var silently took precedence over the embedded copy, so a value in the process environment replaced a build-time-vetted GPU binary with an arbitrary file. Reported as CWE-426 by a security scan. Make the embedded objects authoritative where they exist: AITER_ASM_DIR is only honoured in an embedded build when the builder opts in with -DAITER_ALLOW_ASM_DIR_OVERRIDE, and taking the override now logs a warning. Builds with no embedded map -- which is how the aiter package itself ships, with aiter.jit setting AITER_ASM_DIR to the packaged hsa/ dir on import -- keep loading from disk exactly as before. The disk path also gained the checks it was missing. It rejects a hsaco name that is absolute or contains a '..' component so the join cannot escape the configured directory, requires an ELF magic so a wrong-format file fails here rather than inside the HIP loader, and bounds the size. The size bound also fixes a real crash: tellg() returns -1 on failure and was assigned straight into a size_t, so an unseekable file asked new[] for SIZE_MAX. Test Plan: Syntax-checked the header in all three configurations it now has: ``` clang++ -x hip -nogpuinc -nogpulib --offload-arch=gfx942 -std=c++20 \ -fsyntax-only -D__HIP_PLATFORM_AMD__ -Icsrc/include tu.hip # standalone # + -DAITER_EMBEDDED_HSA_HEADER='"aiter_embedded_hsa.h"' # embedded # + -DAITER_ALLOW_ASM_DIR_OVERRIDE # override ``` Extracted validate_relative_hsaco_path() and the load checks into a standalone harness and ran 19 cases: accepts "fmha_v3_bwd/foo.co", "..foo.co", "a/..b/c.co"; rejects "", "/abs/foo.co", "..", "../foo.co", "a/../../etc/passwd", "a/b/../c.co"; accepts a well-formed ELF and rejects empty, truncated, wrong-magic, and missing files. All pass. Not run on hardware -- no GPU on this machine. A maintainer should confirm an ordinary standalone aiter run still loads its kernels. Authored with assistance from an AI coding assistant. Signed-off-by: Filip Jankovic <filip.jankovic@amd.com>
Contributor
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[Misc] Harden AITER_ASM_DIR code-object loading
Summary
AiterAsmKernelresolves its.cofrom$AITER_ASM_DIRand hands the bytes to__hipRegisterFatBinary. In builds that embed their code objects at compile time, that environment variable silently took precedence over the embedded copy. This makes the embedded objects authoritative where they exist, and adds the validation the disk path was missing.Motivation
A security scan flagged the env-to-code-object flow in
aiter_hip_common.has CWE-426 (untrusted search path). The concrete gap is the precedence order rather than the existence of the env var:AITER_ASM_DIRwas set in the environment, with no warning, and load an arbitrary file from the named directory instead.ck_sdpatarget, which compiles this header with-DAITER_EMBEDDED_HSA_HEADERand generates the embedded map fromthird_party/aiter/hsaat build time. Nothing in PyTorch setsAITER_ASM_DIR, so the variable is purely an external input there.I want to be precise about the severity, because I do not think this is critical: setting an environment variable in the victim process already implies at least as much control as
LD_PRELOADorPYTHONPATHwould give. No privilege boundary is crossed and aiter offers no env sandbox. This is defence in depth — the useful property is that a build which ships vetted binaries cannot be silently redirected away from them — not the closing of a live escalation path.Separately, the disk path had a genuine crash:
tellg()returns-1on failure and was assigned straight into asize_t, so an unseekable file askednew[]forSIZE_MAX.Changes
Precedence. In a build with an embedded map, the embedded object is used.
AITER_ASM_DIRis honoured only if the builder opts in with-DAITER_ALLOW_ASM_DIR_OVERRIDE; taking the override logs a warning naming the directory and the kernel. Without the opt-in, a setAITER_ASM_DIRis ignored and logs a warning saying so, rather than being silently dropped.No behaviour change for standalone aiter. Builds with no embedded map load from disk exactly as before, including the existing fail-closed
AITER_CHECKwhen the variable is unset. This is the path the aiter package itself uses —aiter/jit/core.pysetsAITER_ASM_DIRto the packagedhsa/directory on import — so the normalpip install aiterflow is untouched. Gating the env var off by default would have broken it.Disk-path validation, applied on both the standalone and opted-in override paths:
validate_relative_hsaco_path()rejects a hsaco name that is empty, absolute, or contains a..component, so the join onto the configured directory cannot escape it...as a prefix (..foo.co) is still fine; only a whole component is rejected.SIZE_MAXallocation above.Refactor. The disk-loading body moved into
load_hsaco_from_dir()so both paths share it;load_hsaco_file()is now just the source-selection policy.Deliberate omissions
realpath/std::filesystemcanonicalisation against an install prefix. This header is included from HIP TUs, and there is no install prefix known to the C++ layer in a standalone build — the directory comes from Python. Rejecting..in the relative part gets the containment property that is actually available here without adding a<filesystem>dependency to a widely-included header..soin the stack is loaded.Testing
AITER_ALLOW_ASM_DIR_OVERRIDE),-std=c++20 --offload-arch=gfx942, no warnings from the changed code.validate_relative_hsaco_path()and the load checks extracted into a standalone harness, 19 cases, all passing — acceptsfmha_v3_bwd/foo.co,..foo.co,a/..b/c.co; rejects"",/abs/foo.co,..,../foo.co,a/../../etc/passwd,a/b/../c.co; accepts a well-formed ELF and rejects empty, truncated, wrong-magic and missing files.clang-formatclean over the changed region.No unit tests added: the logic is in a header-only private member of a class that requires a live HIP device to instantiate, and there is no existing C++ test target here to hang it off. Happy to add one if you would like it wired up.
Documentation
AITER_ALLOW_ASM_DIR_OVERRIDElooks right to you, it should probably be mentioned whereverAITER_ASM_DIRis documented for downstream embedders —op_tests/cpp/mha/README.mdis the only place the variable appears in-tree today, and that flow is unaffected.Dependencies
Breaking Changes
None for standalone aiter or for any build without an embedded map.
For a build that embeds code objects and relied on
AITER_ASM_DIRto override them, the override now requires-DAITER_ALLOW_ASM_DIR_OVERRIDEat compile time. I believe PyTorch is the only such consumer today and it does not set the variable, so I expect no downstream fallout — but this is the part worth a maintainer's eye, since you will know of embedders I do not.