Skip to content

all: fix conformance testing failures - #2

Merged
tomhjp merged 9 commits into
mainfrom
tomhjp/nfsv4-protocol-fixes
Oct 8, 2026
Merged

tomhjp merged 9 commits into
mainfrom
tomhjp/nfsv4-protocol-fixes

Conversation

@tomhjp

@tomhjp tomhjp commented Oct 8, 2026

Copy link
Copy Markdown
Member

I had AI run some NFSv4 conformance testing using pynfs and NFSTest, and write up fixes with regression tests. This series of commits is the full set of results. Docs and scripts for repeating the tests are in #1.

tomhjp added 9 commits October 8, 2026 15:18
pynfs CSESS9 and EID6g exposed that client records matched only the
owner/verifier: different AUTH_SYS credentials could confirm an
unconfirmed ID or update another principal's confirmed record.

Save credentials and apply RFC 8881 sections 18.35.4 and 18.36.4 for
confirmation, collisions, and updates. Preserve the SP4_NONE allowance
for other users after confirmation. Also reject invalid EXCHANGE_ID
flags (section 18.35.3; pynfs EID4/EID7).

TestIdentity* covers principal changes, live/expired state, restart,
confirmation retries, and the permitted post-confirmation behavior.
pynfs DSESS9001/DSESS9004 found that an unbound connection could destroy
a session and that the current session could be destroyed before the
compound finished. Other probes found incorrect rejection of a different
client's session on a connection associated with both sessions.

RFC 8881 section 18.37.3 requires an associated connection and final
position only for destruction of the current SEQUENCE session. Track
associations and their cleanup, and enforce BIND's sole-operation rule
(section 18.34.3). TestSessionLifecycle* covers these cases and reconnects.
pynfs SEQ6 reached LOOKUP despite exceeding the negotiated request size,
because of a 1024-byte allowance. Reply and cache limits also omitted RPC
headers. RFC 8881 section 18.36.3 counts complete RPC messages, excluding
transport framing, rather than just COMPOUND bodies.

Use exact sizes and reserve space for error replies before consuming a
slot (section 2.10.6.4). Reject unusable channel sizes and unknown
CREATE_SESSION flags, addressing CSESS25/28 and CSESS15; these negotiation
checks are robustness policy, not all unconditional RFC MUSTs.

TestSessionLimits* checks exact boundaries and same-sequence retries.
Protocol probes reproduced RETRY_UNCACHED_REP on SEQUENCE itself for an
uncached multi-operation retry. Singleton SEQUENCE replies were also lost
when cachethis was false, and retries could substitute a different tag.

RFC 8881 sections 2.10.6.1.1 and 2.10.6.1.3 require successful SEQUENCE
metadata to be cached, with the uncached-reply error on the next operation.
Retain the original tag/metadata and replay without repeating FS calls.

TestSessionReplay* covers wire shape, small caches, in-flight retries,
size boundaries, and callback-status changes. Strengthen TestSequenceSlots
to require the correct two-result uncached reply.
pynfs PUTFH2 accepted nodefs's malformed handle "abc"; only a later
GETATTR discovered the error. RFC 8881 section 15.1.2.1 requires internal
handle validity to be established by PUTFH, but handle formats belong to
the FS, not the protocol layer.

Validate through GetAttr, preserve BADHANDLE versus STALE, and cache the
fetched attributes with their actual mask. Map backend errors that PUTFH
cannot return to SERVERFAULT (section 15.2). Fix malformed nodefs table
handles being classified as STALE.

Regression tests cover arbitrary valid opaque handles, backend errors,
attribute reuse, and obsolete versus malformed handles.
pynfs LKPP1r/LKPP1a succeeded for a regular file and a symlink because
nodefs split the path without checking the object's type.

RFC 8881 section 18.14.3 limits LOOKUPP to directories and named attribute
directories. Check types in both the protocol handler and nodefs, return
NOTDIR or SYMLINK as appropriate, and preserve root NOENT and missing-FH
behavior.

Regression tests cover opaque backends and node trees in both minor
versions, including checks that invalid types never reach LookupParent.
An adapted pynfs probe sent a complete 1536-byte name and received BADXDR
rather than NAMETOOLONG. RFC 8881 section 3.2 defines component4 through
unbounded utf8str_cs, not the 1024-byte opaque owner limit.

Decode names within the already-bounded request, then apply the filesystem
name limit (NAMETOOLONG, section 15.1.7.3). Apply this to LOOKUP, SECINFO,
and named OPEN claims; retain BADXDR for truncation and existing bytewise
filename handling.

TestNameConformance covers length boundaries and truncated XDR in both
minor versions.
pynfs COMP3 exposed acceptance of malformed UTF-8 tags. RFC 8881 sections
16.2.1 and 16.2.4 define the tag as utf8str_cs and specify INVAL for invalid
encoding, including empty compounds.

Validate before executing operations, preserving minor-version mismatch
precedence and tag echo. Keep valid Unicode noncharacters: RFC 3629 allows
their encodings and RFC 8881 section 14.1.5 does not prohibit them. COMP3
still incorrectly expects INVAL for valid U+FFFE; do not adopt that rule.

Tag regressions cover malformed encodings and all 66 noncharacters.
Read-only NFSTest adaptations observed old bytes on an existing fd and a
cached removed name immediately after recall/mutation with actimeo=1.
Both became fresh after revalidation. Traces showed successful recall and
DELEGRETURN before mutation, with correct updated attributes.

RFC 8881 sections 10.4.4 and 10.6 do not make delegation return a flush of
clean client caches. Replace memfs's immediate-visibility claim with the
ordinary-cache/revalidation behavior, and document the Linux observation.
This changes documentation only, not recall ordering or runtime behavior.
@tomhjp
tomhjp force-pushed the tomhjp/nfsv4-protocol-fixes branch from ca04319 to a8183ed Compare October 8, 2026 14:18
@tomhjp
tomhjp merged commit 00c0f62 into main Oct 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants