Historically, we've allowed read() of a directory and some filesystems will accommodate (e.g. ufs/ffs, msdosfs). Some history, courtesy of Warner:
${COPY AND PASTE OF ALL OF IMP'S STATEMENTS}
Disallowing read(2) on a directory has the side-effect of masking application bugs from relying on other implementation's behavior (e.g. Linux) of rejecting these with EISDIR across the board, but allowing it has been a vector for at least one stack disclosure bug in the past[0].
By POSIX, this is implementation-defined whether read() handles directories or not. Popular implementations have chosen to reject them, and this seems sensible: the data you're reading from a directory would seem to not be structured in some unified way across filesystem implementations like with readdir(2), so it seems really hard to rely on this.
With this patch, we will reject most read(2) of a dirfd with EISDIR. Users that know what they're doing can conscientiously set bsd.security.allow_read_dir=1 to allow non-jailed root alone to read(2) directories, as it has proven useful for debugging or recovery.
While we're adding logic pertaining to directory vnodes to vn_io_fault, an additional assertion has also been added to ensure that we're not reaching vn_io_fault with any write request on a directory vnode. Such request would be a logical error in the kernel, and must be debugged rather than allowing it to potentially silently error out.
ZFS will no longer allow read(2) of a directory; what is was previously copying out is decidedly not useful for any debugging or recovery purposes. Allowing read(2) here is also inconsistent with other platforms that support ZFS, at least Solaris and Linux both rejecting such reads.
[0] https://www.freebsd.org/security/advisories/FreeBSD-SA-19:10.ufs.asc