isRunning()/Signal()/Kill()/joinSandboxNetNs() trust a raw PID with no liveness/identity check, so PID reuse after the VMM exits lets urunc signal (and even network-namespace-join) an unrelated host process
Maintainer thường phản hồi trong vòng 1 ngày
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 52/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- go, linux
- Lĩnh vực
- networking, operating-systems, security
Hướng nghiên cứu
Bắt đầu bằng cách lần theo Create và các phương thức vòng đời trong pkg/unikontainers/unikontainers.go, đặc biệt là isRunning, Signal, Kill và joinSandboxNetNs, sau đó kiểm tra checkValidNsPath trong pkg/unikontainers/utils.go và killProcess trong pkg/unikontainers/hypervisors/utils.go. Xem lại cách u.State.Pid được lưu trữ và xác định các bài kiểm thử hiện có hoặc các điểm vào kiểm thử cho những đường dẫn này. Công việc được xem là hoàn tất khi việc tái sử dụng PID luôn bị từ chối trước khi gửi tín hiệu, dừng, xóa hoặc tham gia một network namespace.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Description
urunc records the monitor (VMM) process's PID once, in u.State.Pid, when the container is created, and then uses that raw integer for the rest of the container's lifecycle: Signal(), Kill(), Delete() via isRunning(), and joinSandboxNetNs(). None of these call sites verify that the PID still refers to the same process that was originally launched, they only check whether some process currently holds that PID number.
On Linux, PIDs are recycled. Once the VMM exits and gets reaped, that PID becomes eligible for reuse by any new process on the host. Issue #716 shows urunc containers can sit around for a long time after their VMM has already died, which is exactly the kind of window that makes PID recycling realistic on a busy node.
Relevant code:
pkg/unikontainers/unikontainers.go:1407-1415 (isRunning):
func (u *Unikontainer) isRunning() bool {
vmmType := hypervisors.VmmType(u.State.Annotations[annotHypervisor])
if vmmType != hypervisors.HedgeVmm {
return syscall.Kill(u.State.Pid, syscall.Signal(0)) == nil
}
...
}
pkg/unikontainers/unikontainers.go:794-838 (Signal, Kill):
func (u *Unikontainer) Signal(signal unix.Signal) error {
...
return vmm.Signal(u.State.Pid, signal)
}
func (u *Unikontainer) Kill() error {
err := u.joinSandboxNetNs()
...
err = vmm.Stop(u.State.Pid)
...
err = network.CleanupAllUruncTaps()
...
}
pkg/unikontainers/unikontainers.go:921-948 (joinSandboxNetNs):
if netNsPath == "" {
netNsPath = fmt.Sprintf("/proc/%d/ns/net", u.State.Pid)
err := checkValidNsPath(netNsPath)
...
}
...
fd, err := unix.Open(netNsPath, unix.O_RDONLY|unix.O_CLOEXEC, 0)
...
err = unix.Setns(int(fd), unix.CLONE_NEWNET)
checkValidNsPath (pkg/unikontainers/utils.go:209-220) only does an os.Lstat(path) existence check, never an identity check.
pkg/unikontainers/hypervisors/utils.go:69-92 (killProcess, used by every hypervisor's Stop):
func killProcess(pid int) error {
const timeout = 2 * time.Second
err := unix.Kill(pid, unix.SIGKILL)
...
}
Sends SIGKILL to whatever process currently owns that PID, with no identity check.
None of these five call sites cross check the PID against anything that proves it is still the original VMM, for example /proc/<pid>/stat starttime or cgroup membership, which is a technique other runtimes such as runc rely on for this exact reason.
If the VMM's PID gets reused by an unrelated host process before urunc kill or urunc delete runs:
isRunning()reports true for the unrelated process, soDelete()permanently refuses to clean up the already dead container.Kill()callsjoinSandboxNetNs(), which opens the unrelated process's network namespace and joins it, then callsvmm.Stop(), which SIGKILLs the unrelated process, then runsnetwork.CleanupAllUruncTaps()inside the wrong namespace, removing tap devices that do not belong to this container.
This causes two real failure modes that need no attacker or malicious image author, just ordinary OS PID recycling:
- Host level collateral damage: an unrelated process gets killed, and unrelated network resources are torn down in the wrong netns.
- Stuck containers:
Delete()can refuse indefinitely to remove an already dead container whose PID was reused, leaving orphaned state and blocking CRI or Kubernetes garbage collection, which compounds known issue #716.
Suggested fix: record a lightweight identity token for the VMM PID at Create() time, for example the /proc/<pid>/stat starttime field (which the kernel guarantees changes across PID reuse), and validate it in isRunning(), Signal(), Kill(), and joinSandboxNetNs() before treating the PID as belonging to this container. A mismatch should be treated the same as the process no longer existing.
System info
- Urunc version: main branch
- Arch: any
- VMM: any (Qemu, Firecracker, Cloud Hypervisor, HVT, SPT), any backend going through
killProcess - Unikernel: any
Steps to reproduce
- Start a urunc container with any hypervisor.
u.State.Pidis set to the VMM's host PID, for example 12345. - Let the VMM exit without going through
urunc killorurunc delete(guest panic, VMM OOM kill, or normal completion), so PID 12345 gets reaped and freed. - On a host with enough process churn, an unrelated process ends up receiving PID 12345. This is normal PID reuse behavior on Linux.
- Call
urunc kill <id> 9orurunc delete <id>and observe:isRunning()returns true for the unrelated process, so delete is refused.Kill()joins the unrelated process's network namespace, sends it SIGKILL, and cleans up tap devices in the wrong namespace.
Note on LLM usage
This issue was drafted with the assistance of an LLM (Claude Sonnet 5, Anthropic), which was used to trace the code paths and structure this report. The underlying code, call sites, and failure scenario described above were read and verified directly against the repository by me before filing; the analysis and conclusion are my own responsibility.
- Ngôn ngữ chính
- Go
- Star
- 307
- Fork
- 219
- Merge trung bình
- 1 ngày 19 giờ
- Pull request đã merge (30 ngày)
- 32
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của urunc-dev/urunc
-
Containers handed over to runc cannot be started, killed or deleted when urunc runs without --rootCó thể làm lại được @Daksha1611 đã nhận 8 ngày trước và không có pull request nào đang mở. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
urunc-dev/urunc#1127 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
urunc-deploy cleanup never labels the node, so the cleanup DaemonSet does not runCó thể đã có người làm @Sarthak-Shreshtha01 đã nhận 10 ngày trước. Đang mởbug K8s/Tools
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
Maintainer thường phản hồi trong vòng 1 ngày
-
FreeBSD: docs update and rootfs detectionCó thể đã có người làm @yug105 đã nhận 5 ngày trước. Đang mởdocumentation enhancement Storage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
urunc-dev/urunc#1108 · 6 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Rumprun guests receive &, < and > as \u0026, \u003c and \u003eCó thể đã có người làm @Sarthak-Shreshtha01 đã nhận 16 ngày trước. Đang mởbug Guests
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
urunc-dev/urunc#1074 · 4 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Hooks run concurrently instead of in the listed orderCó thể đã có người làm @anishmehta24 đã nhận 21 ngày trước. Đang mởCore enhancement OCI
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
urunc-dev/urunc#1066 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của urunc-dev/urunc
Issue tương tự
-
[flaky test] TestValidatorCommitterDropsEmptyStatusBatch: submits to the mock VC before its stream is registeredCó thể đã có người làm @liran-funaro đã nhận hôm nay. Đang mởcoordinator flaky-test race-condition testing
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 83/100
hyperledger/fabric-x-committer#876 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
kind/features
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
TencentBlueKing/bk-nodemgr#3804 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
cloudnative-pg/plugin-barman-cloud#1187 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[deliverclient] Remove the unused common/deliverclient packageCó thể đã có người làm @liran-funaro đã nhận hôm nay. Đang mởcode-hygiene
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
hyperledger/fabric-x-common#236 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
consensus feature I2 S4 U2
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 85/100
Maintainer thường phản hồi trong vòng 1 ngày