[CIFS] Prevent OOPs when mounting with remote prefixpath.
Fixes OOPs with message 'kernel BUG at fs/cifs/cifs_dfs_ref.c:274!'. Checks if the prefixpath in an accesible while we are still in cifs_mount and fails with reporting a error if we can't access the prefixpath Should fix Samba bugs 6086 and 5861 and kernel bug 12192 Signed-off-by: Igor Mammedov <niallain@gmail.com> Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
committed by
Steve French
parent
e1f81c8a41
commit
e4cce94c9c
@@ -42,6 +42,7 @@ extern void _FreeXid(unsigned int);
|
|||||||
#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid()));
|
#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid()));
|
||||||
#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
|
#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
|
||||||
extern char *build_path_from_dentry(struct dentry *);
|
extern char *build_path_from_dentry(struct dentry *);
|
||||||
|
extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb);
|
||||||
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
|
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
|
||||||
/* extern void renew_parental_timestamps(struct dentry *direntry);*/
|
/* extern void renew_parental_timestamps(struct dentry *direntry);*/
|
||||||
extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
|
extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
|
||||||
|
@@ -2180,6 +2180,33 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
|
|||||||
"mount option supported"));
|
"mount option supported"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
is_path_accessible(int xid, struct cifsTconInfo *tcon,
|
||||||
|
struct cifs_sb_info *cifs_sb, const char *full_path)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
__u64 inode_num;
|
||||||
|
FILE_ALL_INFO *pfile_info;
|
||||||
|
|
||||||
|
rc = CIFSGetSrvInodeNumber(xid, tcon, full_path, &inode_num,
|
||||||
|
cifs_sb->local_nls,
|
||||||
|
cifs_sb->mnt_cifs_flags &
|
||||||
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
|
if (rc != -EOPNOTSUPP)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
|
||||||
|
if (pfile_info == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
|
||||||
|
0 /* not legacy */, cifs_sb->local_nls,
|
||||||
|
cifs_sb->mnt_cifs_flags &
|
||||||
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
|
kfree(pfile_info);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||||
char *mount_data, const char *devname)
|
char *mount_data, const char *devname)
|
||||||
@@ -2190,6 +2217,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||||||
struct cifsSesInfo *pSesInfo = NULL;
|
struct cifsSesInfo *pSesInfo = NULL;
|
||||||
struct cifsTconInfo *tcon = NULL;
|
struct cifsTconInfo *tcon = NULL;
|
||||||
struct TCP_Server_Info *srvTcp = NULL;
|
struct TCP_Server_Info *srvTcp = NULL;
|
||||||
|
char *full_path;
|
||||||
|
|
||||||
xid = GetXid();
|
xid = GetXid();
|
||||||
|
|
||||||
@@ -2426,6 +2454,23 @@ mount_fail_check:
|
|||||||
cifs_sb->rsize = min(cifs_sb->rsize,
|
cifs_sb->rsize = min(cifs_sb->rsize,
|
||||||
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
|
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
|
||||||
|
|
||||||
|
if (!rc && cifs_sb->prepathlen) {
|
||||||
|
/* build_path_to_root works only when we have a valid tcon */
|
||||||
|
full_path = cifs_build_path_to_root(cifs_sb);
|
||||||
|
if (full_path == NULL) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto mount_fail_check;
|
||||||
|
}
|
||||||
|
rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
|
||||||
|
if (rc) {
|
||||||
|
cERROR(1, ("Path %s in not accessible: %d",
|
||||||
|
full_path, rc));
|
||||||
|
kfree(full_path);
|
||||||
|
goto mount_fail_check;
|
||||||
|
}
|
||||||
|
kfree(full_path);
|
||||||
|
}
|
||||||
|
|
||||||
/* volume_info->password is freed above when existing session found
|
/* volume_info->password is freed above when existing session found
|
||||||
(in which case it is not needed anymore) but when new sesion is created
|
(in which case it is not needed anymore) but when new sesion is created
|
||||||
the password ptr is put in the new session structure (in which case the
|
the password ptr is put in the new session structure (in which case the
|
||||||
|
@@ -621,7 +621,7 @@ static const struct inode_operations cifs_ipc_inode_ops = {
|
|||||||
.lookup = cifs_lookup,
|
.lookup = cifs_lookup,
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *build_path_to_root(struct cifs_sb_info *cifs_sb)
|
char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
|
||||||
{
|
{
|
||||||
int pplen = cifs_sb->prepathlen;
|
int pplen = cifs_sb->prepathlen;
|
||||||
int dfsplen;
|
int dfsplen;
|
||||||
@@ -678,7 +678,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
|||||||
return inode;
|
return inode;
|
||||||
|
|
||||||
cifs_sb = CIFS_SB(inode->i_sb);
|
cifs_sb = CIFS_SB(inode->i_sb);
|
||||||
full_path = build_path_to_root(cifs_sb);
|
full_path = cifs_build_path_to_root(cifs_sb);
|
||||||
if (full_path == NULL)
|
if (full_path == NULL)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user