# DF-3864 — `amdgpu_vm_init()` error paths dereference `vm->root.base.bo` before it is assigned (NULL deref → kernel panic)

File: `sys/dev/drm/amd/amdgpu/amdgpu_vm.c` — `amdgpu_vm_init()` (3048-3148)

## Root cause

`vm->root.base.bo` is only published by `amdgpu_vm_bo_base_init()` at
amdgpu_vm.c:3107 — i.e. AFTER `amdgpu_bo_reserve()` (3097) and
`amdgpu_vm_clear_bo()` (3101) succeed. But the error labels assume it is
already set:

```c
	r = amdgpu_bo_reserve(root, true);
	if (r)
		goto error_free_root;			/* 3097-3099: base.bo == NULL */

	r = amdgpu_vm_clear_bo(adev, vm, root, ...);
	if (r)
		goto error_unreserve;			/* 3101-3105: base.bo == NULL */

	amdgpu_vm_bo_base_init(&vm->root.base, vm, root);	/* 3107 */
	...
error_unreserve:
	amdgpu_bo_unreserve(vm->root.base.bo);	/* 3137: ttm_bo_unreserve(&NULL->tbo) */
error_free_root:
	amdgpu_bo_unref(&vm->root.base.bo->shadow); /* 3140: &NULL->shadow */
	amdgpu_bo_unref(&vm->root.base.bo);
```

- clear_bo failure → `amdgpu_bo_unreserve(NULL)` → `ttm_bo_unreserve(&NULL->tbo)`
  (amdgpu_object.h:165-168) → lock/atomic ops at a near-NULL address → panic.
- reserve failure → `amdgpu_bo_unref(&vm->root.base.bo->shadow)` →
  `&NULL->shadow` = small constant → `*bo` load at low address → panic.

## Reachability

`amdgpu_vm_init()` runs on EVERY DRM device open
(amdgpu_kms.c:990, `amdgpu_driver_open_kms`). `amdgpu_vm_clear_bo()` allocates
an IB from the shared, bounded IB pool (amdgpu_ib.c:279-287,
`AMDGPU_IB_POOL_SIZE*64*1024`) and does TTM validation — both fail under
memory/IB pressure, which an unprivileged render-node user can induce with
concurrent context creation + IB consumers. Unprivileged local DoS
(kernel panic) on amdgpu hardware.

The same defect exists in upstream Linux ~4.20 (verified against v4.20
sources — same labels, same ordering).

## Trigger

`vm_init_error_race.c` — hammers the render node with concurrent
open()/close() (each open runs amdgpu_vm_init) while an IB-pool consumer
runs, forcing `amdgpu_job_alloc_with_ib` inside clear_bo to fail on some
open. On hardware with a DEBUG kernel the panic backtrace lands in
`amdgpu_bo_unreserve`/`ttm_bo_unreserve` called from `amdgpu_vm_init`.

## Fix

`fix.diff` uses the local `root` pointer on both error labels (the variable
that IS valid on every path reaching them).
