# DF-0602 — VERDICT

## Verdict: NOT REPRODUCED (latent code defect in dead/orphaned/non-compiling file)

The cited code defect is **real and confirmed by source-level trace**, but it
is **unreachable on this guest** (and on any standard DragonFlyBSD kernel
configuration) because the containing file is dead, orphaned, non-compiling
code. No runtime reproduction is possible. No escalation is possible. This is
a **latent-defect / hardening item** — exactly as the finding markdown states.

## Mechanism (confirmed by source trace)

`sys/netgraph7/ng_source.c:479-487` — the `NGM_SOURCE_GET_COUNTER` handler:

```c
case NGM_SOURCE_GET_COUNTER:
    {
        uint8_t index = *(uint8_t *)msg->data;     /* line 481: NO arglen check */
        struct ng_source_embed_cnt_info *embed;

        if (index >= NG_SOURCE_COUNTERS) {          /* line 484 */
            error = EINVAL;
            goto done;
        }
        ...
```

`msg->data` is the flexible-array member at the end of `struct ng_mesg`
(`sys/netgraph7/ng_message.h:81`). The message buffer was allocated by the
sender via `NG_MKMESSAGE` as `kmalloc(sizeof(struct ng_mesg) + (len), ...)`
(`ng_message.h:394`); `header.arglen` is taken verbatim from the wire and is
**not** re-validated by the receiver before the switch dispatches on
`header.cmd`. With `header.arglen == 0`, the `data[]` area is zero bytes and
`*(uint8_t *)msg->data` reads 1 byte past the requested allocation.

This is a genuine code defect because **every other data-bearing command in
the same switch validates `arglen` before touching `msg->data`**:

| Command              | Line  | Check                                          |
|----------------------|-------|------------------------------------------------|
| `NGM_SOURCE_START`   | 388   | `if (msg->header.arglen != sizeof(uint64_t))`  |
| `NGM_SOURCE_SETIFACE`| 409   | `if (msg->header.arglen < 2)`                  |
| `NGM_SOURCE_SETPPS`  | 421   | `if (msg->header.arglen != sizeof(uint32_t))`  |
| `NGM_SOURCE_SET_TIMESTAMP` | 436 | `if (msg->header.arglen != sizeof(*embed))` |
| `NGM_SOURCE_SET_COUNTER`   | 463 | `if (msg->header.arglen != sizeof(*embed))` |
| `NGM_ETHER_GET_IFNAME`     | 513 | `if (msg->header.arglen < 2)`               |
| **`NGM_SOURCE_GET_COUNTER`** | **481** | **(none — reads `msg->data` first)** |

`GET_COUNTER` is the lone exception.

## Why it does NOT reproduce / is unreachable on this guest

The file is dead/orphaned/non-compiling. Verified facts (all confirmed on the
`with-src` baseline, kernel `6.5-DEVELOPMENT #0`):

1. **Not in `sys/conf/files`** — `grep -c ng_source /usr/src/sys/conf/files`
   ⇒ `0`. There is no `netgraph7_source` (or similar) option that would pull
   it in. The file is therefore never compiled into the static kernel.
2. **Not in `sys/netgraph7/Makefile` SUBDIR** — `grep -c ng_source .../Makefile`
   ⇒ `0`. It is never built as a loadable KLD module.
3. **No standalone module Makefile** — `sys/netgraph7/ng_source.c` has no
   sibling `Makefile`, unlike `echo/`, `pppoe/`, `eiface/`, etc.
4. **Compile error at line 743** — `ifq->ifq_maxlen` / `ifq->ifq_len` reference
   an undeclared identifier (the local is `ifsq`). The file would not compile
   even if added to the build.
5. **Not present as a loadable module on the running guest** —
   `ls /boot/kernel/ng_source*` ⇒ "No such file or directory";
   `kldload -n ng_source` ⇒ "can't load ng_source: No such file or directory"
   (rc=1).
6. **`NETGRAPH7` is not in `X86_64_GENERIC`** — `grep -in netgraph
   sys/config/X86_64_GENERIC` ⇒ no matches; the whole netgraph7 subsystem
   is opt-in via `options NETGRAPH7_*` and is off on the default kernel.

Because the vulnerable code can never execute on this guest (or any standard
DFBSD kernel), there is no runtime to reproduce against. This is identical in
root cause and impact to the sibling finding **DF-0601** (same file, same
dead-code classification, already recorded `not_reproduced`).

## Impact assessment (latent, if the file were ever compiled in)

- The OOB read is **1 byte** of `kmalloc` slab padding (sizeof(struct ng_mesg)
  == 56 → 64-byte slab; with arglen==0 the read lands in the 8-byte bucket
  padding, not unmapped memory, so it does **not** crash).
- The read value only steers the subsequent `index >= NG_SOURCE_COUNTERS`
  bounds check (i.e. which of 4 already-privileged counter slots is returned,
  or `EINVAL`). It is **not echoed back** to the sender — `NG_MKRESPONSE`
  copies from `sc->embed_counter[index]`, not from `msg->data`.
- **No info leak, no crash, no privilege change.** Negligible latent impact.
- This is correctly classified **Info** severity.

## No escalation (Phase 6 — N/A)

This is an OOB-read in **dead code**. There is no live primitive to
characterize, no slab bucket to groom, no victim object to corrupt, no
pointer to redirect. Phase 6 does not apply.

## Recommended fix (authored as `fix.diff`)

Add an `arglen` lower-bound check mirroring the pattern of every sibling
command, placed **before** the `msg->data` dereference. The check uses
`< sizeof(index)` (matching `SETIFACE`/`GET_IFNAME`'s lower-bound style rather
than exact-equality, since `GET_COUNTER` consumes only 1 byte and should
tolerate a slightly over-long message):

```diff
@@ -478,9 +478,15 @@
 		    }
 		case NGM_SOURCE_GET_COUNTER:
 		    {
-			uint8_t index = *(uint8_t *)msg->data;
+			uint8_t index;
 			struct ng_source_embed_cnt_info *embed;
 
+			if (msg->header.arglen < sizeof(index)) {
+				error = EINVAL;
+				goto done;
+			}
+			index = *(uint8_t *)msg->data;
+
 			if (index >= NG_SOURCE_COUNTERS) {
```

This **matches** the finding markdown's `## Recommended fix` proposal (same
placement, same `EINVAL`/`goto done` semantics, same `sizeof(index)` lower
bound). The finding's diff also notes the duplicate `embed` declaration; my
version keeps the single existing declaration and is surgical.

## Fix validation: `not_testable`

A kernel build + runtime test of this single-fix diff is **not possible** on
this guest, for reasons entirely outside this finding's scope:

1. The file is not in `sys/conf/files`, so `make nativekernel` never compiles
   it — patching the arglen check has zero effect on the produced kernel.
2. The file has an **unrelated** compile error at line 743 (`ifq` undeclared)
   that must be fixed first before the file can compile at all.
3. Adding the file to `conf/files` and fixing the line-743 typo are
   prerequisites that belong to a separate "revive netgraph7/ng_source" effort,
   not to this single-bug fix.

**What WAS validated:**
- `patch -p1 --dry-run --forward < fix.diff` ⇒ succeeds ("Hunk #1 succeeded
  at 478") on both the host read-only `sys/` tree and the in-guest
  `/usr/src` tree.
- Applied to in-guest `/usr/src`, the patched region reads exactly as intended
  (arglen check precedes the dereference).
- Reverted cleanly (`patch -R`), leaving the source pristine for the
  `with-src` reset.

Because the bug is in dead code and cannot be exercised at runtime on any
standard kernel, `fix_status = "not_testable"` is the honest classification
(per the rubric: "PoC can't run on guest at all (latent/remote/missing
module); you validated the diff applies + compiles [logic] only, and traced
that it closes the code path").

## PoC changes

None. The finding markdown and seeded `README.md` correctly state that no PoC
can be built today (file does not compile). I confirmed this and added no
trigger source — there is nothing to trigger. The only artifact authored is
`fix.diff` (the verified arglen-check patch).

## References (confirmed during verification)

- `sys/netgraph7/ng_source.c:479-487` — vulnerable `GET_COUNTER` handler
  (no arglen check before `msg->data` deref).
- `sys/netgraph7/ng_source.c:388,409,421,436,463,513` — every sibling command
  validates `arglen` first (the contrast that proves the defect).
- `sys/netgraph7/ng_source.c:743` — unrelated `ifq` typo that prevents
  compilation.
- `sys/netgraph7/ng_message.h:69-81` — `struct ng_mesg` with flexible-array
  `data[]`.
- `sys/netgraph7/ng_message.h:392-407` — `NG_MKMESSAGE` allocates
  `sizeof(struct ng_mesg) + len` (so `len==0` ⇒ zero-byte `data[]`).
- `sys/conf/files` — `ng_source` absent (grep ⇒ 0).
- `sys/netgraph7/Makefile` — `ng_source` absent from SUBDIR (grep ⇒ 0).
- `sys/config/X86_64_GENERIC` — no `NETGRAPH7` options.
