Repository navigation
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.
Harden cloud-hypervisor privileged runtime path and add explicit human-review warning #52757
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Harden cloud-hypervisor privileged runtime path and add explicit human-review warning #52757
Changes from 4 commits
c7b3bdb3f5eeec8daa546d98767cf35c15c2fc078dFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
There are no files selected for viewing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ACL verification is too brittle:
getfaclcommonly emitsuser:UID:rw-with a trailing\t#effective:rw-comment when a mask is present, so your anchored regex will reject a valid ACL and fail the setup on otherwise healthy runners.💡 Why this blocks the change
setfacl -m u:${runner_uid}:rw /dev/kvmcan create an entry that still prints an#effective:suffix depending on the existing ACL mask. In that casegrep -Eq "^user:${runner_uid}:rw-?$"does not match, even though the runner really does have the intended access. That turns a hardening check into a false-negative gate on some hosts.A safer verification is to tolerate the optional effective-permissions annotation, for example:
or, even better, query the permissions with a tool/output format that is not sensitive to cosmetic formatting differences.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[/diagnosing-bugs] The ACL grep pattern
^user:${runner_uid}:rw-?$uses an unquoted regex inside[[ ]]which is fine, but the trailing-?makes the dash optional — it would match bothrwandrw-. GNUgetfacl -cpalways emits the three-character mask (rw-), so the optional-is benign. However, a simpler and more explicit pattern would be^user:${runner_uid}:rw-$to exactly match the expected ACL format and fail loudly if the format changes.💡 Suggestion
This documents the expected ACL mask precisely and would surface a regression if
getfacloutput format changes.@copilot please address this.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
L47: shrink: awk one-liner to detect symlink/hardlink tar entries.
grep -Eq '^[lh]'on the same table, 1 line.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[/diagnosing-bugs] The
awksymlink/hardlink check inverts its exit code in a non-obvious way (exit 0when a link is found,exit 1when none are found), which the wrappingifthen inverts again. This double-negation is easy to misread and may silently pass a malicious archive ifawkis not available or thearchive_tablevariable is empty.💡 Clearer alternative
Or more idiomatically:
Also add a guard for empty
archive_tablebefore this block.@copilot please address this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[/codebase-design]
exit 1insidevalidate_extracted_fileterminates the entire shell script directly rather than returning a non-zero status to the caller. This is intentional here, but it prevents callers from wrapping the function in conditional logic and makes the function harder to unit-test in isolation.💡 Suggestion
If the exit-on-failure behaviour is deliberate (consistent with the surrounding script style), add a brief comment explaining that. If reusability is desired, replace
exit 1withreturn 1and let callers dovalidate_extracted_file "$x" || exit 1.@copilot please address this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This path check can be bypassed by a tarball that stores the payload under a symlinked directory:
resolve_pathreturnsrealpath, butvalidate_extracted_fileonly string-prefixes against${extract_dir}, so a file extracted throughbundle/link -> /somewherestill passes asbundle/link/fileeven though the resolved file lives outside the extraction root.💡 Why this matters
The new preflight blocks link entries from
tar -tvzf, but the post-extraction guard should still validate the resolved canonical path rather than the original spelling. Right now the check is:If
fileis/tmp/.../bundle/link/cloud-hypervisorandlinkpoints elsewhere, the prefix test succeeds whilerealpath "$file"is outside${extract_dir}. That leaves the safety property dependent on the tar listing parser never missing a link variant.Please compare canonicalized paths instead, e.g.
realpath "$file"must start with$(realpath "$extract_dir")/, so the containment check stays correct even if a symlink slips through or the extraction directory already contains one.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
L120-126: shrink: case/esac to check directory prefix.
[[ "${file}" != "${extract_dir}"/* ]] && { echo ...; exit 1; }, no esac needed.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The path-containment check
"${extract_dir}"/*compares a raw (un-canonicalized)extract_diragainstrealpath-canonicalized file paths. Ifbundle_rootcontains symlinks or..segments, the glob pattern won't match the canonicalized path, and the containment guard can be bypassed.Suggest canonicalizing
extract_dirat declaration time:extract_dir="$(realpath -m "${bundle_root}/bundle")"@copilot please address this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[/diagnosing-bugs] The
casepattern"${extract_dir}"/*does not reject paths like"${extract_dir}/../outside"— a resolved path can still escape the extraction root ifextract_diritself contains..components or if the archive entry is constructed to match the prefix literally.💡 Fix
Use
realpath --relative-baseor compare canonicalized paths to rule out traversal:This eliminates any
..bypass through symlink resolution or path component manipulation.@copilot please address this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[/diagnosing-bugs]
wis closed twice — once int.Cleanup(line 236) and again here — which can race or double-close the pipe's write end, causing an unpredictable test panic.💡 Fix
Remove the explicit
w.Close()at line 242 and lett.Cleanupown the pipe lifecycle. Read the pipe output insidet.Cleanupafter closingw:This mirrors the pattern the adjacent test already uses after its own cleanup fix in this diff.
@copilot please address this.