NFS4 wrong behavior with symbolic link
Trond Myklebust
trond.myklebust at fys.uio.no
Wed May 2 10:45:07 EDT 2007
On Wed, 2007-05-02 at 10:36 -0400, Charland, Denis wrote:
>
> > -----Original Message-----
> > From: Trond Myklebust [mailto:trond.myklebust at fys.uio.no]
> > Sent: Wednesday, May 02, 2007 10:30 AM
> > To: Charland, Denis
> > Cc: nfsv4 at linux-nfs.org
> > Subject: RE: NFS4 wrong behavior with symbolic link
> >
> >
> > On Wed, 2007-05-02 at 10:15 -0400, Charland, Denis wrote:
> > >
> > > Can you reproduce the problem on your side?
> > >
> > > Denis
> >
> > no.
> >
> > Trond
> >
> >
>
> Can it be a kernel related problem (NFSV4 implementation in the kernel)?
>
> Denis
It might be, but if so it is likely to have been fixed. I believe I
recall some problems along the lines of what you report but there is
nothing in the git tree...
Ah, found the patch in the bkcvs stuff....
Could you see if the following patch applies?
Trond
------
commit 253c81e92706a0703b68e7fcbb7d3b19c7c8f413
Author: trond.myklebust <trond.myklebust>
Date: Mon Aug 23 22:07:46 2004 +0000
NFSv4: Fix the symlink overflow bug.
Signed-off-by: Trond Myklebust <trond.myklebust at fys.uio.no>
BKrev: 412a6ab2AfDsvnWnWUbu2N_R1NOJsA
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index b8f4be0..36366f6 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1299,19 +1299,6 @@ nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,
dir->i_ino, dentry->d_name.name, symname);
- error = -ENAMETOOLONG;
- switch (NFS_PROTO(dir)->version) {
- case 2:
- if (strlen(symname) > NFS2_MAXPATHLEN)
- goto out;
- break;
- case 3:
- if (strlen(symname) > NFS3_MAXPATHLEN)
- goto out;
- default:
- break;
- }
-
#ifdef NFS_PARANOIA
if (dentry->d_inode)
printk("nfs_proc_symlink: %s/%s not negative!\n",
@@ -1341,8 +1328,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
d_drop(dentry);
}
unlock_kernel();
-
-out:
return error;
}
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 67c0793..0bf9af7 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -540,6 +540,8 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
};
int status;
+ if (path->len > NFS3_MAXPATHLEN)
+ return -ENAMETOOLONG;
dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
dir_attr.valid = 0;
fattr->valid = 0;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1fab109..8d54d4f 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1092,12 +1092,14 @@ static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
.fattr = fattr,
};
struct rpc_message msg = {
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK],
.rpc_argp = &arg,
.rpc_resp = &res,
};
int status;
+ if (path->len > NFS4_MAXPATHLEN)
+ return -ENAMETOOLONG;
arg.u.symlink = path;
fattr->valid = 0;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 029e5b1..c0a4080 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -84,6 +84,7 @@ static int nfs_stat_to_errno(int);
((3+NFS4_FHSIZE) >> 2))
#define encode_getattr_maxsz (op_encode_hdr_maxsz + 3)
#define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2))
+#define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2))
#define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz)
#define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \
nfs4_fattr_bitmap_maxsz)
@@ -118,8 +119,13 @@ static int nfs_stat_to_errno(int);
#define encode_link_maxsz (op_encode_hdr_maxsz + \
nfs4_name_maxsz)
#define decode_link_maxsz (op_decode_hdr_maxsz + 5)
+#define encode_symlink_maxsz (op_encode_hdr_maxsz + \
+ 1 + nfs4_name_maxsz + \
+ nfs4_path_maxsz + \
+ nfs4_fattr_bitmap_maxsz)
+#define decode_symlink_maxsz (op_decode_hdr_maxsz + 8)
#define encode_create_maxsz (op_encode_hdr_maxsz + \
- 2 + 2 * nfs4_name_maxsz + \
+ 2 + nfs4_name_maxsz + \
nfs4_fattr_bitmap_maxsz)
#define decode_create_maxsz (op_decode_hdr_maxsz + 8)
#define NFS4_enc_compound_sz (1024) /* XXX: large enough? */
@@ -313,6 +319,16 @@ static int nfs_stat_to_errno(int);
decode_savefh_maxsz + \
decode_putfh_maxsz + \
decode_link_maxsz)
+#define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_symlink_maxsz + \
+ encode_getattr_maxsz + \
+ encode_getfh_maxsz)
+#define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_symlink_maxsz + \
+ decode_getattr_maxsz + \
+ decode_getfh_maxsz)
#define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_create_maxsz + \
@@ -1244,6 +1260,14 @@ out:
}
/*
+ * Encode SYMLINK request
+ */
+static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
+{
+ return nfs4_xdr_enc_create(req, p, args);
+}
+
+/*
* Encode GETATTR request
*/
static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args)
@@ -3204,6 +3228,14 @@ out:
}
/*
+ * Decode SYMLINK response
+ */
+static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
+{
+ return nfs4_xdr_dec_create(rqstp, p, res);
+}
+
+/*
* Decode GETATTR response
*/
static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res)
@@ -3793,6 +3825,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(REMOVE, enc_remove, dec_remove),
PROC(RENAME, enc_rename, dec_rename),
PROC(LINK, enc_link, dec_link),
+ PROC(SYMLINK, enc_symlink, dec_symlink),
PROC(CREATE, enc_create, dec_create),
PROC(PATHCONF, enc_pathconf, dec_pathconf),
PROC(STATFS, enc_statfs, dec_statfs),
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 8dc6a98..279ddad 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -400,6 +400,8 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
};
int status;
+ if (path->len > NFS2_MAXPATHLEN)
+ return -ENAMETOOLONG;
dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
fattr->valid = 0;
status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0);
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 8dec3e4..2b53e25 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -18,6 +18,7 @@
#define NFS4_VERIFIER_SIZE 8
#define NFS4_FHSIZE 128
+#define NFS4_MAXPATHLEN PATH_MAX
#define NFS4_MAXNAMLEN NAME_MAX
#define NFS4_ACCESS_READ 0x0001
@@ -372,6 +373,7 @@ enum {
NFSPROC4_CLNT_REMOVE,
NFSPROC4_CLNT_RENAME,
NFSPROC4_CLNT_LINK,
+ NFSPROC4_CLNT_SYMLINK,
NFSPROC4_CLNT_CREATE,
NFSPROC4_CLNT_PATHCONF,
NFSPROC4_CLNT_STATFS,
More information about the NFSv4
mailing list