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


_______________________________________________
bugs mailing list
[email protected]
http://lists.rtems.org/mailman/listinfo/bugs

Reply via email to