LibBSD | rtems_bsd_sysgen_read() reads a vnode out of a descriptor that has none (#104)

Sang Woo Kim (@sngwkim915) gitlab at rtems.org
Tue Jul 28 06:54:19 UTC 2026



Issue created by Sang Woo Kim: https://gitlab.rtems.org/rtems/pkg/rtems-libbsd/-/work_items/104



## Summary

`read()` on a socket intermittently answers `EINVAL` and, in a libevent program, wedges the event loop. Which descriptors are hit depends on the numbers a program happens to get, so it looks like a race. Present on `7-freebsd-14`, `6-freebsd-14` and `6-freebsd-12`.

`rtems_bsd_sysgen_read()` is the `read_h` of all four handler tables and starts with

```c
struct vnode *vp = rtems_bsd_libio_iop_to_vnode(iop);
...
if (vp->v_type == VDIR)
        return kern_getdirentries(...);
```

but `node_access` carries a `struct vnode *` only for descriptors opened through the VFS — `rtems_bsd_libio_loc_set_vnode()` is called only on the `dirops` and `fileops` paths. For a socket, a pipe or a kqueue, `rtems_bsd_libio_iop_set_bsd_descriptor()` parks the iop itself there. Reading `v_type` out of that is a read several hundred bytes past the end of a 44-byte `rtems_libio_tt`, landing inside a neighbouring iop; when that word happens to be `VDIR`, `read()` on a socket calls `kern_getdirentries()` and answers `EINVAL`. Seen on libevent's notify socketpair, 32 times in one run:

```
BSDREAD PUN fd=13 bsd=6 iop=0x610ee8 v_type=2
```

Fix: `rtems_bsd_is_libbsd_nvops(iop)` is already the discriminator — it is true exactly for the two handler tables whose `node_access` is a vnode. Have `rtems_bsd_libio_iop_to_vnode()` answer NULL for the rest rather than hand back a punned pointer. [7-freebsd-14](https://github.com/physwkim/rtems-libbsd/commit/d4f32ebb1a1455a5800fcf0dd4574856afbfce2a) · [6-freebsd-14](https://github.com/physwkim/rtems-libbsd/commit/aaa929f60ca06aaec9c0e8798884ff6758c3a029) · [6-freebsd-12](https://github.com/physwkim/rtems-libbsd/commit/e1c3bbd6d8147ac2acfd5b9c94823be2d63e361f)

## Steps to reproduce

```c
for (i = 0; i < 48; i++) {
        socketpair(AF_UNIX, SOCK_STREAM, 0, p[i]);
        write(p[i][1], "x", 1);
        if (read(p[i][0], b, sizeof b) != 1)
                printf("fd %d: errno %d\n", p[i][0], errno);   /* EINVAL */
}
```

`recv()` on the same descriptor succeeds — the two differ only in that `read()` goes through `rtems_bsd_sysgen_read()`.

-- 
View it on GitLab: https://gitlab.rtems.org/rtems/pkg/rtems-libbsd/-/work_items/104
You're receiving this email because of your account on gitlab.rtems.org. Unsubscribe from this thread: https://gitlab.rtems.org/-/sent_notifications/4-54senvnc1wdrtgv6y43f9mo5f-k/unsubscribe | Manage all notifications: https://gitlab.rtems.org/-/profile/notifications | Help: https://gitlab.rtems.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/bugs/attachments/20260728/97a9b8b5/attachment-0001.htm>


More information about the bugs mailing list