nfs_closedir can be called without preceding nfs_opendir -> crash

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


Attachment: nfs_7.c
Description: Binary data


[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux