# DF-4752 — gpio(4) gpio_unregister leaks the master clone unit + struct gpio_driver

**File:** `sys/dev/misc/gpio/gpio.c` (pass 2)

## What

`gpio_unregister()` (gpio.c:587-617) has two resource-accounting defects that
are *distinct from* the known pin-unit get-vs-put bug (DF-1845, gpio.c:596-600):

1. **Master device clone unit never returned.** `gpio_register()` allocates a
   unit from `DEVFS_CLONE_BITMAP(gpio)` for the master cdev (gpio.c:573-575,
   `make_dev(..., "gpio/%s%d/master", ...)`). `gpio_unregister()` destroys that
   dev (gpio.c:602) but never calls `devfs_clone_bitmap_put()` for it — the
   unit stays allocated forever. (The pin loop right above at least attempts a
   bitmap call, albeit the wrong one.)

2. **`struct gpio_driver` + name never freed, dropped from the list while
   siblings may still use it.** `gpd` is allocated once per *driver name*
   (gpio.c:559-565, shared by all controllers with the same `driver_name`;
   `gpd->name = kstrdup(...)`). `gpio_unregister()` does
   `devfs_clone_bitmap_put(&gpd->unit_bitmap, ...); LIST_REMOVE(gpd, link);`
   (gpio.c:609-611) with **no kfree of gpd or gpd->name, and no refcount**:
   - every unregister leaks `sizeof(struct gpio_driver)` + name (M_TEMP);
   - if two controllers share the name, the first unregister unlinks the
     shared `gpd` while the sibling is still live; the sibling's own
     unregister then finds no list entry and silently skips its bitmap put.

## Impact

Permanent kernel heap leak per controller attach/detach cycle plus monotonic
clone-unit consumption (the bitmap auto-extends — `devfs_clone_bitmap_get()`
is called with limit 0, which never fails — so this is unbounded creep, not a
hard exhaustion). Trigger is privileged (driver detach / kldunload), hence
**Low** severity, consistent with the DF-1845/DF-1846 family.

## Reproduce (hardware/config-gated)

Run `./trigger.sh` on a system with `device gpio` + a GPIO controller
(nsclpcsio/PC87366 etc.). On the audit guest the framework is not compiled in
(`optional gpio`, not in X86_64_GENERIC), so the trigger exits 3 (SKIP) —
defect verified by source trace; fix compile-validated (see VERDICT.md).

## Fix

`fix.diff` (applies to `sys/dev/misc/gpio/gpio.c`): put the master unit back,
refcount `gpd`, free on last reference. Compile-validated as a kernel module
against the guest's 6.5-DEVELOPMENT source with `-Werror` (fix_build.log).
