aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Mammedov <niallain@gmail.com>2009-02-10 06:10:26 -0500
committerSteve French <sfrench@us.ibm.com>2009-02-20 22:36:21 -0500
commite4cce94c9c8797b08faf6a79396df4d175e377fa (patch)
tree6eb306603652bf08ca10fef4f899332f30d71e09
parente1f81c8a417be466e85a38b61679aa6860ec7331 (diff)
[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>
-rw-r--r--fs/cifs/cifsproto.h1
-rw-r--r--fs/cifs/connect.c45
-rw-r--r--fs/cifs/inode.c4
3 files changed, 48 insertions, 2 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 382ba6298809..ec9f9c1c7d88 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -42,6 +42,7 @@ extern void _FreeXid(unsigned int);
42#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid())); 42#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid()));
43#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));} 43#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
44extern char *build_path_from_dentry(struct dentry *); 44extern char *build_path_from_dentry(struct dentry *);
45extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb);
45extern char *build_wildcard_path_from_dentry(struct dentry *direntry); 46extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
46/* extern void renew_parental_timestamps(struct dentry *direntry);*/ 47/* extern void renew_parental_timestamps(struct dentry *direntry);*/
47extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, 48extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 005df85219a8..da0f4ffa0613 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2180,6 +2180,33 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
2180 "mount option supported")); 2180 "mount option supported"));
2181} 2181}
2182 2182
2183static int
2184is_path_accessible(int xid, struct cifsTconInfo *tcon,
2185 struct cifs_sb_info *cifs_sb, const char *full_path)
2186{
2187 int rc;
2188 __u64 inode_num;
2189 FILE_ALL_INFO *pfile_info;
2190
2191 rc = CIFSGetSrvInodeNumber(xid, tcon, full_path, &inode_num,
2192 cifs_sb->local_nls,
2193 cifs_sb->mnt_cifs_flags &
2194 CIFS_MOUNT_MAP_SPECIAL_CHR);
2195 if (rc != -EOPNOTSUPP)
2196 return rc;
2197
2198 pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
2199 if (pfile_info == NULL)
2200 return -ENOMEM;
2201
2202 rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
2203 0 /* not legacy */, cifs_sb->local_nls,
2204 cifs_sb->mnt_cifs_flags &
2205 CIFS_MOUNT_MAP_SPECIAL_CHR);
2206 kfree(pfile_info);
2207 return rc;
2208}
2209
2183int 2210int
2184cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, 2211cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2185 char *mount_data, const char *devname) 2212 char *mount_data, const char *devname)
@@ -2190,6 +2217,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2190 struct cifsSesInfo *pSesInfo = NULL; 2217 struct cifsSesInfo *pSesInfo = NULL;
2191 struct cifsTconInfo *tcon = NULL; 2218 struct cifsTconInfo *tcon = NULL;
2192 struct TCP_Server_Info *srvTcp = NULL; 2219 struct TCP_Server_Info *srvTcp = NULL;
2220 char *full_path;
2193 2221
2194 xid = GetXid(); 2222 xid = GetXid();
2195 2223
@@ -2426,6 +2454,23 @@ mount_fail_check:
2426 cifs_sb->rsize = min(cifs_sb->rsize, 2454 cifs_sb->rsize = min(cifs_sb->rsize,
2427 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); 2455 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2428 2456
2457 if (!rc && cifs_sb->prepathlen) {
2458 /* build_path_to_root works only when we have a valid tcon */
2459 full_path = cifs_build_path_to_root(cifs_sb);
2460 if (full_path == NULL) {
2461 rc = -ENOMEM;
2462 goto mount_fail_check;
2463 }
2464 rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
2465 if (rc) {
2466 cERROR(1, ("Path %s in not accessible: %d",
2467 full_path, rc));
2468 kfree(full_path);
2469 goto mount_fail_check;
2470 }
2471 kfree(full_path);
2472 }
2473
2429 /* volume_info->password is freed above when existing session found 2474 /* volume_info->password is freed above when existing session found
2430 (in which case it is not needed anymore) but when new sesion is created 2475 (in which case it is not needed anymore) but when new sesion is created
2431 the password ptr is put in the new session structure (in which case the 2476 the password ptr is put in the new session structure (in which case the
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index bcf7b5184664..7342bfb02ae0 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -621,7 +621,7 @@ static const struct inode_operations cifs_ipc_inode_ops = {
621 .lookup = cifs_lookup, 621 .lookup = cifs_lookup,
622}; 622};
623 623
624static char *build_path_to_root(struct cifs_sb_info *cifs_sb) 624char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
625{ 625{
626 int pplen = cifs_sb->prepathlen; 626 int pplen = cifs_sb->prepathlen;
627 int dfsplen; 627 int dfsplen;
@@ -678,7 +678,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
678 return inode; 678 return inode;
679 679
680 cifs_sb = CIFS_SB(inode->i_sb); 680 cifs_sb = CIFS_SB(inode->i_sb);
681 full_path = build_path_to_root(cifs_sb); 681 full_path = cifs_build_path_to_root(cifs_sb);
682 if (full_path == NULL) 682 if (full_path == NULL)
683 return ERR_PTR(-ENOMEM); 683 return ERR_PTR(-ENOMEM);
684 684