Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4462dc02 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  cifs: guard against hardlinking directories
parents 002baeec 3d694380
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -502,6 +502,7 @@ struct dfs_info3_param {
#define CIFS_FATTR_DFS_REFERRAL		0x1
#define CIFS_FATTR_DFS_REFERRAL		0x1
#define CIFS_FATTR_DELETE_PENDING	0x2
#define CIFS_FATTR_DELETE_PENDING	0x2
#define CIFS_FATTR_NEED_REVAL		0x4
#define CIFS_FATTR_NEED_REVAL		0x4
#define CIFS_FATTR_INO_COLLISION	0x8


struct cifs_fattr {
struct cifs_fattr {
	u32		cf_flags;
	u32		cf_flags;
+19 −2
Original line number Original line Diff line number Diff line
@@ -715,6 +715,16 @@ cifs_find_inode(struct inode *inode, void *opaque)
	if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
	if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
		return 0;
		return 0;


	/*
	 * uh oh -- it's a directory. We can't use it since hardlinked dirs are
	 * verboten. Disable serverino and return it as if it were found, the
	 * caller can discard it, generate a uniqueid and retry the find
	 */
	if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) {
		fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
		cifs_autodisable_serverino(CIFS_SB(inode->i_sb));
	}

	return 1;
	return 1;
}
}


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


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


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


	inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
	inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);

	/* we have fattrs in hand, update the inode */
	if (inode) {
	if (inode) {
		/* was there a problematic inode number collision? */
		if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
			iput(inode);
			fattr->cf_uniqueid = iunique(sb, ROOT_I);
			fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
			goto retry_iget5_locked;
		}

		cifs_fattr_to_inode(inode, fattr);
		cifs_fattr_to_inode(inode, fattr);
		if (sb->s_flags & MS_NOATIME)
		if (sb->s_flags & MS_NOATIME)
			inode->i_flags |= S_NOATIME | S_NOCMTIME;
			inode->i_flags |= S_NOATIME | S_NOCMTIME;