linux/fs
Jeff Layton f6488c9ba5 nfs: don't allow nfs_find_actor to match inodes of the wrong type
Benny Halevy reported the following oops when testing RHEL6:

<7>nfs_update_inode: inode 892950 mode changed, 0040755 to 0100644
<1>BUG: unable to handle kernel NULL pointer dereference at (null)
<1>IP: [<ffffffffa02a52c5>] nfs_closedir+0x15/0x30 [nfs]
<4>PGD 81448a067 PUD 831632067 PMD 0
<4>Oops: 0000 [#1] SMP
<4>last sysfs file: /sys/kernel/mm/redhat_transparent_hugepage/enabled
<4>CPU 6
<4>Modules linked in: fuse bonding 8021q garp ebtable_nat ebtables be2iscsi iscsi_boot_sysfs bnx2i cnic uio cxgb4i cxgb4 cxgb3i libcxgbi cxgb3 mdio ib_iser rdma_cm ib_cm iw_cm ib_sa ib_mad ib_core ib_addr iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi softdog bridge stp llc xt_physdev ipt_REJECT nf_conntrack_ipv4 nf_defrag_ipv4 xt_multiport iptable_filter ip_tables ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables ipv6 dm_round_robin dm_multipath objlayoutdriver2(U) nfs(U) lockd fscache auth_rpcgss nfs_acl sunrpc vhost_net macvtap macvlan tun kvm_intel kvm be2net igb dca ptp pps_core microcode serio_raw sg iTCO_wdt iTCO_vendor_support i7core_edac edac_core shpchp ext4 mbcache jbd2 sd_mod crc_t10dif ahci dm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
<4>
<4>Pid: 6332, comm: dd Not tainted 2.6.32-358.el6.x86_64 #1 HP ProLiant DL170e G6  /ProLiant DL170e G6
<4>RIP: 0010:[<ffffffffa02a52c5>]  [<ffffffffa02a52c5>] nfs_closedir+0x15/0x30 [nfs]
<4>RSP: 0018:ffff88081458bb98  EFLAGS: 00010292
<4>RAX: ffffffffa02a52b0 RBX: 0000000000000000 RCX: 0000000000000003
<4>RDX: ffffffffa02e45a0 RSI: ffff88081440b300 RDI: ffff88082d5f5760
<4>RBP: ffff88081458bba8 R08: 0000000000000000 R09: 0000000000000000
<4>R10: 0000000000000772 R11: 0000000000400004 R12: 0000000040000008
<4>R13: ffff88082d5f5760 R14: ffff88082d6e8800 R15: ffff88082f12d780
<4>FS:  00007f728f37e700(0000) GS:ffff8800456c0000(0000) knlGS:0000000000000000
<4>CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
<4>CR2: 0000000000000000 CR3: 0000000831279000 CR4: 00000000000007e0
<4>DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
<4>DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
<4>Process dd (pid: 6332, threadinfo ffff88081458a000, task ffff88082fa0e040)
<4>Stack:
<4> 0000000040000008 ffff88081440b300 ffff88081458bbf8 ffffffff81182745
<4><d> ffff88082d5f5760 ffff88082d6e8800 ffff88081458bbf8 ffffffffffffffea
<4><d> ffff88082f12d780 ffff88082d6e8800 ffffffffa02a50a0 ffff88082d5f5760
<4>Call Trace:
<4> [<ffffffff81182745>] __fput+0xf5/0x210
<4> [<ffffffffa02a50a0>] ? do_open+0x0/0x20 [nfs]
<4> [<ffffffff81182885>] fput+0x25/0x30
<4> [<ffffffff8117e23e>] __dentry_open+0x27e/0x360
<4> [<ffffffff811c397a>] ? inotify_d_instantiate+0x2a/0x60
<4> [<ffffffff8117e4b9>] lookup_instantiate_filp+0x69/0x90
<4> [<ffffffffa02a6679>] nfs_intent_set_file+0x59/0x90 [nfs]
<4> [<ffffffffa02a686b>] nfs_atomic_lookup+0x1bb/0x310 [nfs]
<4> [<ffffffff8118e0c2>] __lookup_hash+0x102/0x160
<4> [<ffffffff81225052>] ? selinux_inode_permission+0x72/0xb0
<4> [<ffffffff8118e76a>] lookup_hash+0x3a/0x50
<4> [<ffffffff81192a4b>] do_filp_open+0x2eb/0xdd0
<4> [<ffffffff8104757c>] ? __do_page_fault+0x1ec/0x480
<4> [<ffffffff8119f562>] ? alloc_fd+0x92/0x160
<4> [<ffffffff8117de79>] do_sys_open+0x69/0x140
<4> [<ffffffff811811f6>] ? sys_lseek+0x66/0x80
<4> [<ffffffff8117df90>] sys_open+0x20/0x30
<4> [<ffffffff8100b072>] system_call_fastpath+0x16/0x1b
<4>Code: 65 48 8b 04 25 c8 cb 00 00 83 a8 44 e0 ff ff 01 5b 41 5c c9 c3 90 55 48 89 e5 53 48 83 ec 08 0f 1f 44 00 00 48 8b 9e a0 00 00 00 <48> 8b 3b e8 13 0c f7 ff 48 89 df e8 ab 3d ec e0 48 83 c4 08 31
<1>RIP  [<ffffffffa02a52c5>] nfs_closedir+0x15/0x30 [nfs]
<4> RSP <ffff88081458bb98>
<4>CR2: 0000000000000000

I think this is ultimately due to a bug on the server. The client had
previously found a directory dentry. It then later tried to do an atomic
open on a new (regular file) dentry. The attributes it got back had the
same filehandle as the previously found directory inode. It then tried
to put the filp because it failed the aops tests for O_DIRECT opens, and
oopsed here because the ctx was still NULL.

Obviously the root cause here is a server issue, but we can take steps
to mitigate this on the client. When nfs_fhget is called, we always know
what type of inode it is. In the event that there's a broken or
malicious server on the other end of the wire, the client can end up
crashing because the wrong ops are set on it.

Have nfs_find_actor check that the inode type is correct after checking
the fileid. The fileid check should rarely ever match, so it should only
rarely ever get to this check. In the case where we have a broken
server, we may see two different inodes with the same i_ino, but the
client should be able to cope with them without crashing.

This should fix the oops reported here:

    https://bugzilla.redhat.com/show_bug.cgi?id=913660

Reported-by: Benny Halevy <bhalevy@tonian.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
2013-02-27 17:28:20 -08:00
..
9p The following changes since commit 4cbe5a555fa58a79b6ecbb6c531b8bab0650778d: 2012-10-12 09:59:23 +09:00
adfs adfs: drop vmtruncate 2012-12-20 14:00:01 -05:00
affs affs: drop vmtruncate 2012-12-20 14:00:01 -05:00
afs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2012-10-02 20:25:04 -07:00
autofs4 Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace 2012-12-17 15:44:47 -08:00
befs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2012-10-02 20:25:04 -07:00
bfs bfs: drop vmtruncate 2012-12-20 14:00:01 -05:00
btrfs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs 2013-01-25 10:55:21 -08:00
cachefiles FS-Cache: Mark cancellation of in-progress operation 2012-12-20 22:34:00 +00:00
ceph Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client 2012-12-20 14:00:13 -08:00
cifs fs/cifs/cifs_dfs_ref.c: fix potential memory leakage 2013-01-22 23:58:16 -06:00
coda fs: push rcu_barrier() from deactivate_locked_super() to filesystems 2012-10-02 21:35:55 -04:00
configfs lseek: the "whence" argument is called "whence" 2012-12-17 17:15:12 -08:00
cramfs
debugfs debugfs: convert gid= argument from decimal, not octal 2013-01-11 05:56:01 -08:00
devpts TTY: devpts, document devpts inode operations 2012-10-22 16:50:13 -07:00
dlm dlm: fix lvb invalidation conditions 2012-11-16 11:20:42 -06:00
ecryptfs fs/ecryptfs/crypto.c: make ecryptfs_encode_for_filename() static 2012-12-18 10:10:13 -06:00
efs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2012-10-02 20:25:04 -07:00
exofs exofs: don't leak io_state and pages on read error 2012-12-14 12:17:32 +02:00
exportfs Merge branch 'for-3.8' of git://linux-nfs.org/~bfields/linux 2012-12-20 14:04:11 -08:00
ext2 ext2: fix return values on parse_options() failure 2012-10-09 23:23:53 +02:00
ext3 lseek: the "whence" argument is called "whence" 2012-12-17 17:15:12 -08:00
ext4 ext4: remove duplicate call to ext4_bread() in ext4_init_new_dir() 2013-01-06 23:40:25 -05:00
f2fs f2fs: use _safe() version of list_for_each 2013-01-22 10:49:00 +09:00
fat fat: fix incorrect function comment 2012-12-20 17:40:20 -08:00
freevxfs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2012-10-02 20:25:04 -07:00
fscache FS-Cache: Clear remaining page count on retrieval cancellation 2012-12-20 22:35:15 +00:00
fuse fuse: remove unused variable in fuse_try_move_page() 2013-01-17 13:09:59 +01:00
gfs2 GFS2: fix skip unlock condition 2013-01-28 09:49:15 +00:00
hfs hfs: drop vmtruncate 2012-12-20 14:00:01 -05:00
hfsplus Merge branch 'akpm' (Andrew's patch-bomb) 2012-12-20 20:00:43 -08:00
hostfs Merge branch 'for-linus-37rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml 2012-10-10 11:15:20 +09:00
hpfs hpfs: drop vmtruncate 2012-12-20 18:40:00 -05:00
hppfs pidns: Use task_active_pid_ns where appropriate 2012-11-19 05:59:09 -08:00
hugetlbfs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2012-12-13 12:00:02 -08:00
isofs tmpfs,ceph,gfs2,isofs,reiserfs,xfs: fix fh_len checking 2012-10-09 23:33:55 -04:00
jbd jbd: don't wake kjournald unnecessarily 2013-01-14 22:50:45 +01:00
jbd2 Various bug fixes for ext4. Perhaps the most serious bug fixed is one 2013-01-02 09:57:34 -08:00
jffs2 jffs2: hold erase_completion_lock on exit 2012-11-18 11:59:01 +02:00
jfs jfs: drop vmtruncate 2012-12-20 18:40:52 -05:00
lockd NLM: Ensure that we resend all pending blocking locks after a reclaim 2013-02-19 12:18:27 -05:00
logfs logfs: drop vmtruncate 2012-12-20 18:40:53 -05:00
minix minix: drop vmtruncate 2012-12-20 18:40:53 -05:00
ncpfs ncpfs: drop vmtruncate 2012-12-20 18:40:54 -05:00
nfs nfs: don't allow nfs_find_actor to match inodes of the wrong type 2013-02-27 17:28:20 -08:00
nfs_common
nfsd Revert "nfsd: warn on odd reply state in nfsd_vfs_read" 2012-12-21 17:07:45 -08:00
nilfs2 nilfs2: drop vmtruncate 2012-12-20 18:40:54 -05:00
nls
notify Merge branch 'for-next' of git://git.infradead.org/users/eparis/notify 2012-12-20 20:11:52 -08:00
ntfs ntfs: drop vmtruncate 2012-12-20 18:40:55 -05:00
ocfs2 ocfs2: drop vmtruncate 2012-12-20 14:00:01 -05:00
omfs omfs: drop vmtruncate 2012-12-20 14:00:01 -05:00
openpromfs fs: push rcu_barrier() from deactivate_locked_super() to filesystems 2012-10-02 21:35:55 -04:00
proc mempolicy: remove arg from mpol_parse_str, mpol_to_str 2013-01-02 09:27:10 -08:00
pstore pstore: remove __dev* attributes. 2013-01-03 15:57:14 -08:00
qnx4 Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2012-10-02 20:25:04 -07:00
qnx6 Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2012-10-02 20:25:04 -07:00
quota quota: Use the pre-processor to compile out quotactl_cmd_write when !CONFIG_BLOCK 2012-12-13 16:33:24 +01:00
ramfs
reiserfs reiserfs: drop vmtruncate 2012-12-20 14:00:01 -05:00
romfs fs: push rcu_barrier() from deactivate_locked_super() to filesystems 2012-10-02 21:35:55 -04:00
squashfs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2012-10-02 20:25:04 -07:00
sysfs Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace 2012-12-17 15:44:47 -08:00
sysv sysv: drop vmtruncate 2012-12-20 14:00:01 -05:00
ubifs ubifs: use prandom_bytes 2012-12-17 17:15:26 -08:00
udf UDF: Fix a null pointer dereference in udf_sb_free_partitions 2013-01-14 22:53:47 +01:00
ufs ufs: drop vmtruncate 2012-12-20 14:00:01 -05:00
xfs xfs: Fix xfs_swap_extents() after removal of xfs_flushinval_pages() 2013-01-28 16:05:10 -06:00
Kconfig fuse: Move CUSE Kconfig entry from fs/Kconfig into fs/fuse/Kconfig 2013-01-17 13:08:45 +01:00
Kconfig.binfmt coredump: make core dump functionality optional 2012-10-06 03:05:15 +09:00
Makefile f2fs: update Kconfig and Makefile 2012-12-11 13:43:42 +09:00
aio.c
anon_inodes.c
attr.c userns: Allow chown and setgid preservation 2012-11-20 04:17:24 -08:00
bad_inode.c lseek: the "whence" argument is called "whence" 2012-12-17 17:15:12 -08:00
binfmt_aout.c get rid of pt_regs argument of ->load_binary() 2012-11-28 21:53:38 -05:00
binfmt_elf.c binfmt_elf: fix corner case kfree of uninitialized data 2012-12-17 17:15:19 -08:00
binfmt_elf_fdpic.c get rid of pt_regs argument of ->load_binary() 2012-11-28 21:53:38 -05:00
binfmt_em86.c exec: use -ELOOP for max recursion depth 2012-12-17 17:15:23 -08:00
binfmt_flat.c get rid of pt_regs argument of ->load_binary() 2012-11-28 21:53:38 -05:00
binfmt_misc.c exec: do not leave bprm->interp on stack 2012-12-20 17:40:19 -08:00
binfmt_script.c exec: do not leave bprm->interp on stack 2012-12-20 17:40:19 -08:00
binfmt_som.c get rid of pt_regs argument of ->load_binary() 2012-11-28 21:53:38 -05:00
bio-integrity.c
bio.c vfs: fix: don't increase bio_slab_max if krealloc() fails 2012-10-22 22:00:26 +02:00
block_dev.c lseek: the "whence" argument is called "whence" 2012-12-17 17:15:12 -08:00
buffer.c vfs: add missing virtual cache flush after editing partial pages 2013-01-14 13:17:50 -08:00
char_dev.c char_dev: pin parent kobject 2012-10-22 08:50:37 +03:00
compat.c vfs: define struct filename and have getname() return it 2012-10-12 20:14:55 -04:00
compat_binfmt_elf.c coredump: extend core dump note section to contain file names of mapped files 2012-10-06 03:05:17 +09:00
compat_ioctl.c Merge 3.7-rc3 into tty-next 2012-10-29 09:00:57 -07:00
coredump.c do_coredump(): get rid of pt_regs argument 2012-11-29 00:01:25 -05:00
coredump.h coredump: update coredump-related headers 2012-10-06 03:05:15 +09:00
dcache.c vfs: d_obtain_alias() needs to use "/" as default name. 2012-12-20 18:49:10 -05:00
dcookies.c
direct-io.c direct-io: don't read inode->i_blkbits multiple times 2012-11-29 12:38:44 -08:00
drop_caches.c
eventfd.c fs, eventfd: add procfs fdinfo helper 2012-12-17 17:15:27 -08:00
eventpoll.c epoll: prevent missed events on EPOLL_CTL_MOD 2013-01-02 09:16:43 -08:00
exec.c fs/exec.c: work around icc miscompilation 2013-01-11 14:54:55 -08:00
fcntl.c Fix F_DUPFD_CLOEXEC breakage 2012-10-09 15:52:31 +09:00
fhandle.c Merge branch 'for-3.8' of git://linux-nfs.org/~bfields/linux 2012-12-20 14:04:11 -08:00
fifo.c
file.c misc: remove __dev* attributes. 2013-01-03 15:57:16 -08:00
file_table.c fs: Fix imbalance in freeze protection in mark_files_ro() 2012-12-20 13:57:36 -05:00
filesystems.c vfs: define struct filename and have getname() return it 2012-10-12 20:14:55 -04:00
fs-writeback.c writeback: fix a typo in comment 2012-12-12 17:38:34 -08:00
fs_struct.c kill daemonize() 2012-11-28 21:49:02 -05:00
generic_acl.c
inode.c mm: redefine address_space.assoc_mapping 2012-12-11 17:22:26 -08:00
internal.h writeback: put unused inodes to LRU after writeback completion 2012-11-26 17:41:24 -08:00
ioctl.c
ioprio.c
libfs.c vfs: drop vmtruncate 2012-12-20 18:46:29 -05:00
locks.c UAPI Disintegration 2012-10-09 2012-10-09 18:35:22 -04:00
mbcache.c
mount.h proc: Usable inode numbers for the namespace file descriptors. 2012-11-20 04:19:49 -08:00
mpage.c
namei.c vfs: fix renameat to retry on ESTALE errors 2012-12-20 18:50:05 -05:00
namespace.c vfs, freeze: use ACCESS_ONCE() to guard access to ->mnt_flags 2012-12-20 13:36:18 -05:00
no-block.c
open.c vfs: make fchownat retry once on ESTALE errors 2012-12-20 18:50:07 -05:00
pipe.c
pnode.c
pnode.h vfs: Only support slave subtrees across different user namespaces 2012-11-19 05:59:20 -08:00
posix_acl.c
proc_namespace.c
read_write.c sendfile: allows bypassing of notifier events 2012-12-20 17:40:21 -08:00
read_write.h compat: fs: Generic compat_sys_sendfile implementation 2012-10-02 21:35:55 -04:00
readdir.c
select.c
seq_file.c seq_file: fix new kernel-doc warnings 2013-01-10 14:35:24 -08:00
signalfd.c fs, epoll: add procfs fdinfo helper 2012-12-17 17:15:27 -08:00
splice.c tcp: fix MSG_SENDPAGE_NOTLAST logic 2013-01-06 20:58:13 -08:00
stack.c
stat.c vfs: fix readlinkat to retry on ESTALE 2012-12-20 18:50:01 -05:00
statfs.c vfs: fix user_statfs to retry once on ESTALE errors 2012-12-20 18:50:07 -05:00
super.c vfs: drop lock/unlock super 2012-10-09 23:33:39 -04:00
sync.c
timerfd.c
utimes.c vfs: allow utimensat() calls to retry once on an ESTALE error 2012-12-20 18:50:08 -05:00
xattr.c vfs: make lremovexattr retry once on ESTALE error 2012-12-20 18:50:11 -05:00
xattr_acl.c userns: Fix posix_acl_file_xattr_userns gid conversion 2012-10-12 13:16:48 -07:00