lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <254871306829495@web62.yandex.ru>
Date:	Tue, 31 May 2011 12:11:34 +0400
From:	Dmitry Dmitriev <dimondmm@...dex.ru>
To:	viro@...iv.linux.org.uk, linux-fsdevel@...r.kernel.org,
	linux-kernel@...r.kernel.org
Subject: PROBLEM: Corrupting d_count of target dentry, when rename directory to the directory which is mount point, or when rename directory which is mount point to the existing directory.

Hello!

When rename directory to the directory which is mount point( or rename directory which is mount point to the existing directory ), the target directory dentry d_count become corrupted. This problem occur on 2.6.35 kernel. In this case next call to the dget function report BUG( see below ).

The problem in vfs_rename_dir function( fs/namei.c module ):
2577        target = new_dentry->d_inode;
2578        if (target)
2579                mutex_lock(&target->i_mutex);
2580        if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
2581                error = -EBUSY;
2582        else {
2583                if (target)
2584                        dentry_unhash(new_dentry);
2585                error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
2586        }
2587        if (target) {
2588                if (!error) {
2589                        target->i_flags |= S_DEAD;
2590                        dont_mount(new_dentry);
2591                }
2592                mutex_unlock(&target->i_mutex);
2593                if (d_unhashed(new_dentry))
2594                        d_rehash(new_dentry);
2595                dput(new_dentry);
2596        }

When new_dentry exist, i.e. 'target' is not NULL, and a mount point( or old dentry is a mount point ), then function set 'error' variable to -EBUSY( line 2581 ). After that function will call dput function for new_dentry( line 2595 ) without corresponding dget. In this case d_count of dentry become corrupted. In case when old dentry and new dentry are not mount points, dget for new dentry is called in dentry_unhash function.

Therefore if old dentry or new dentry are mount points, then after execution of vfs_rename_dir function, new dentry will have a corrupted d_count and next call to the dget function can cause a BUG on line 338:
 335static inline struct dentry *dget(struct dentry *dentry)
 336{
 337        if (dentry) {
 338                BUG_ON(!atomic_read(&dentry->d_count));
 339                atomic_inc(&dentry->d_count);
 340        }
 341        return dentry;
 342}

Script reproducing this problem on 2.6.35 kernel is attached.
BUG report is below:
[  679.726754] ------------[ cut here ]------------
[  679.726758] kernel BUG at /build/buildd/linux-2.6.35/include/linux/dcache.h:338!
[  679.726760] invalid opcode: 0000 [#1] SMP 
[  679.726763] last sysfs file: /sys/devices/virtual/block/loop1/queue/hw_sector_size
[  679.726764] Modules linked in: nls_iso8859_1 vfat fat nls_cp437 cifs sha1_generic arc4 ppp_mppe ppp_async crc_ccitt binfmt_misc kvm_intel kvm parport_pc ppdev nfs lockd fscache nfs_acl auth_rpcgss sunrpc i915 drm_kms_helper drm snd_hda_codec_intelhdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq snd_timer snd_seq_device joydev asus_atk0110 snd intel_agp psmouse soundcore i2c_algo_bit snd_page_alloc serio_raw video output agpgart lp parport hid_a4tech usbhid hid r8169 ahci libahci mii
[  679.726793] 
[  679.726795] Pid: 2463, comm: rmdir Not tainted 2.6.35-23-generic #41-Ubuntu P7H55D-M PRO/System Product Name
[  679.726798] EIP: 0060:[<c0221d8d>] EFLAGS: 00210246 CPU: 1
[  679.726803] EIP is at dentry_unhash+0x7d/0x90
[  679.726805] EAX: 00000000 EBX: ee540bb0 ECX: c02a43e0 EDX: 00000000
[  679.726806] ESI: f2f9e0a0 EDI: ee540bb0 EBP: ef10df1c ESP: ef10df14
[  679.726808]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
[  679.726810] Process rmdir (pid: 2463, ti=ef10c000 task=f037d8d0 task.ti=ef10c000)
[  679.726811] Stack:
[  679.726812]  fffffff0 f2f9e0a0 ef10df30 c0223126 ef10df3c ee540bb0 00000000 ef10dfa4
[  679.726816] <0> c0224d2d ef10df94 f6bcde00 f2f4ed48 00271d65 00000003 f0187002 00000000
[  679.726820] <0> 00000004 00000000 00000000 00000000 00800004 00000071 00000001 f2874d80
[  679.726824] Call Trace:
[  679.726828]  [<c0223126>] ? vfs_rmdir+0x66/0xe0
[  679.726831]  [<c0224d2d>] ? do_rmdir+0xdd/0xf0
[  679.726835]  [<c0216d1c>] ? filp_close+0x4c/0x80
[  679.726837]  [<c0224d95>] ? sys_rmdir+0x15/0x20
[  679.726841]  [<c05c99f4>] ? syscall_call+0x7/0xb
[  679.726842] Code: 8d b6 00 00 00 00 8b 43 04 a8 10 75 dc 83 c8 10 8b 53 18 89 43 04 8b 43 14 85 c0 89 02 74 03 89 50 04 c7 43 18 00 02 20 00 eb be <0f> 0b eb fe eb 0d 90 90 90 90 90 90 90 90 90 90 90 90 90 55 89 
[  679.726864] EIP: [<c0221d8d>] dentry_unhash+0x7d/0x90 SS:ESP 0068:ef10df14
[  679.726868] ---[ end trace a1a44cd5949fd802 ]---


Regards,
Dmitry
Download attachment "bug.sh" of type "application/octet-stream" (397 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ