Skip to content

Commit 4462dc0

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: cifs: guard against hardlinking directories
2 parents 002baee + 3d69438 commit 4462dc0

File tree

2 files changed

+20
-2
lines changed

2 files changed

+20
-2
lines changed

fs/cifs/cifsglob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ struct dfs_info3_param {
502502
#define CIFS_FATTR_DFS_REFERRAL 0x1
503503
#define CIFS_FATTR_DELETE_PENDING 0x2
504504
#define CIFS_FATTR_NEED_REVAL 0x4
505+
#define CIFS_FATTR_INO_COLLISION 0x8
505506

506507
struct cifs_fattr {
507508
u32 cf_flags;

fs/cifs/inode.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,16 @@ cifs_find_inode(struct inode *inode, void *opaque)
715715
if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
716716
return 0;
717717

718+
/*
719+
* uh oh -- it's a directory. We can't use it since hardlinked dirs are
720+
* verboten. Disable serverino and return it as if it were found, the
721+
* caller can discard it, generate a uniqueid and retry the find
722+
*/
723+
if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) {
724+
fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
725+
cifs_autodisable_serverino(CIFS_SB(inode->i_sb));
726+
}
727+
718728
return 1;
719729
}
720730

@@ -734,15 +744,22 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
734744
unsigned long hash;
735745
struct inode *inode;
736746

747+
retry_iget5_locked:
737748
cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid));
738749

739750
/* hash down to 32-bits on 32-bit arch */
740751
hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
741752

742753
inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
743-
744-
/* we have fattrs in hand, update the inode */
745754
if (inode) {
755+
/* was there a problematic inode number collision? */
756+
if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
757+
iput(inode);
758+
fattr->cf_uniqueid = iunique(sb, ROOT_I);
759+
fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
760+
goto retry_iget5_locked;
761+
}
762+
746763
cifs_fattr_to_inode(inode, fattr);
747764
if (sb->s_flags & MS_NOATIME)
748765
inode->i_flags |= S_NOATIME | S_NOCMTIME;

0 commit comments

Comments
 (0)