From 12020a68df837423b8a750ce55dce4b4fb441a4d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 23 Aug 2004 10:07:46 -0400 Subject: [PATCH] NFSv4: Fix the symlink overflow bug. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 15 --------------- fs/nfs/nfs3proc.c | 2 ++ fs/nfs/nfs4proc.c | 4 +++- fs/nfs/nfs4xdr.c | 35 ++++++++++++++++++++++++++++++++++- fs/nfs/proc.c | 2 ++ include/linux/nfs4.h | 2 ++ 6 files changed, 43 insertions(+), 17 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index b8f4be07de64..36366f6b1d87 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 67c0793ef143..0bf9af7678b7 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 1fab10970a28..8d54d4f343c7 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 029e5b107e6c..c0a4080db681 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 + \ @@ -1243,6 +1259,14 @@ out: return status; } +/* + * 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 */ @@ -3203,6 +3227,14 @@ out: return status; } +/* + * 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 */ @@ -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 8dc6a981c586..279ddad6ee4e 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 8dec3e456d02..2b53e25f25f7 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, -- 2.39.5