2021-11-10 16:54:16

by rtm

[permalink] [raw]
Subject: nfs_closedir can be called without preceding nfs_opendir -> crash

It's possible for nfs_closedir() to be called without
filp->private_data ever having been set. This causes a crash when
put_nfs_open_dir_context() calls list_del on filp->private_data->list.

I have a test program that provokes this crash (with a misbehaving NFS
server). Here's my partial understanding of what happens:

* A program tries to create a new file "x".
* The NFS v4 server replies OK to the open RPC, but includes
attributes with an invalid (huge) fattr4.type.
* This causes decode_attr_type() to not set NFS_ATTR_FATTR_TYPE, so
the type test in nfs4_open_done() isn't executed, which would
ordinarily prevent all this from happening.
* But the open mostly succeeds, and allocates an inode;
_nfs4_proc_open() sends another getattr RPC to get the type &c.
* The server replies to this second getattr with type=NF4DIR,
and nfs_fhget() sets inode->i_fop = nfs_dir_operations.
But i_fop.open=nfs_diropen won't be called because this inode
is stale...
* The NF4DIR causes nfs_finish_open() to return EOPENSTALE,
which causes do_filp_open() to retry the open.
* The NFS server replies to this open with attribute type=NF4REG.
* nfs_find_actor() allocates a new struct inode, since the type is
different.
* Meanwhile, path_openat() had called fput(file) for the original
stale open, which causes a background task eventually to call
___fput, which makes the nfs_closedir() call that crashes.

One way to view this is that inode->i_fop gets out of sync with
file->private_data.

I've attached my test program:

# cc nfs_7.c
# ./a.out
...
[ 26.691442] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
[ 26.704718] Oops [#1]
[ 26.709193] Modules linked in:
[ 26.715724] CPU: 0 PID: 73 Comm: sh Not tainted 5.15.0-rc7-dirty #20
[ 26.725572] Hardware name: ucbbar,riscvemu-bare (DT)
[ 26.733242] epc : __list_del_entry_valid+0x8/0xa0
[ 26.741500] ra : nfs_closedir+0x28/0x5c
[ 26.748036] epc : ffffffff802ed742 ra : ffffffff80206bea sp : ffffffd00059bd60
...
[ 26.866512] status: 0000000200000121 badaddr: 0000000000000000 cause: 000000000000000d
[ 26.877462] [<ffffffff802ed742>] __list_del_entry_valid+0x8/0xa0
[ 26.887319] [<ffffffff80206bea>] nfs_closedir+0x28/0x5c
[ 26.895619] [<ffffffff8012b4c6>] __fput+0x78/0x1c6
[ 26.903952] [<ffffffff8012b67c>] ____fput+0xc/0x14
[ 26.912274] [<ffffffff8002344c>] task_work_run+0x68/0xa4
[ 26.920516] [<ffffffff80003df0>] do_notify_resume+0x74/0x356
[ 26.930376] [<ffffffff80003054>] ret_from_exception+0x0/0xc



Attachments:
nfs_7.c (18.13 kB)