Commit 12020a68 authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Fix the symlink overflow bug.

Signed-off-by: default avatarTrond Myklebust <trond.myklebust@fys.uio.no>
parent 31d7dc1b
...@@ -1299,19 +1299,6 @@ nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ...@@ -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, dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,
dir->i_ino, dentry->d_name.name, symname); 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 #ifdef NFS_PARANOIA
if (dentry->d_inode) if (dentry->d_inode)
printk("nfs_proc_symlink: %s/%s not negative!\n", printk("nfs_proc_symlink: %s/%s not negative!\n",
...@@ -1341,8 +1328,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name); ...@@ -1341,8 +1328,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
d_drop(dentry); d_drop(dentry);
} }
unlock_kernel(); unlock_kernel();
out:
return error; return error;
} }
......
...@@ -540,6 +540,8 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, ...@@ -540,6 +540,8 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
}; };
int status; int status;
if (path->len > NFS3_MAXPATHLEN)
return -ENAMETOOLONG;
dprintk("NFS call symlink %s -> %s\n", name->name, path->name); dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
dir_attr.valid = 0; dir_attr.valid = 0;
fattr->valid = 0; fattr->valid = 0;
......
...@@ -1092,12 +1092,14 @@ static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, ...@@ -1092,12 +1092,14 @@ static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
.fattr = fattr, .fattr = fattr,
}; };
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK],
.rpc_argp = &arg, .rpc_argp = &arg,
.rpc_resp = &res, .rpc_resp = &res,
}; };
int status; int status;
if (path->len > NFS4_MAXPATHLEN)
return -ENAMETOOLONG;
arg.u.symlink = path; arg.u.symlink = path;
fattr->valid = 0; fattr->valid = 0;
......
...@@ -84,6 +84,7 @@ static int nfs_stat_to_errno(int); ...@@ -84,6 +84,7 @@ static int nfs_stat_to_errno(int);
((3+NFS4_FHSIZE) >> 2)) ((3+NFS4_FHSIZE) >> 2))
#define encode_getattr_maxsz (op_encode_hdr_maxsz + 3) #define encode_getattr_maxsz (op_encode_hdr_maxsz + 3)
#define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) #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 nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz)
#define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \ #define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \
nfs4_fattr_bitmap_maxsz) nfs4_fattr_bitmap_maxsz)
...@@ -118,8 +119,13 @@ static int nfs_stat_to_errno(int); ...@@ -118,8 +119,13 @@ static int nfs_stat_to_errno(int);
#define encode_link_maxsz (op_encode_hdr_maxsz + \ #define encode_link_maxsz (op_encode_hdr_maxsz + \
nfs4_name_maxsz) nfs4_name_maxsz)
#define decode_link_maxsz (op_decode_hdr_maxsz + 5) #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 + \ #define encode_create_maxsz (op_encode_hdr_maxsz + \
2 + 2 * nfs4_name_maxsz + \ 2 + nfs4_name_maxsz + \
nfs4_fattr_bitmap_maxsz) nfs4_fattr_bitmap_maxsz)
#define decode_create_maxsz (op_decode_hdr_maxsz + 8) #define decode_create_maxsz (op_decode_hdr_maxsz + 8)
#define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */
...@@ -313,6 +319,16 @@ static int nfs_stat_to_errno(int); ...@@ -313,6 +319,16 @@ static int nfs_stat_to_errno(int);
decode_savefh_maxsz + \ decode_savefh_maxsz + \
decode_putfh_maxsz + \ decode_putfh_maxsz + \
decode_link_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 + \ #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \ encode_putfh_maxsz + \
encode_create_maxsz + \ encode_create_maxsz + \
...@@ -1243,6 +1259,14 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct n ...@@ -1243,6 +1259,14 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct n
return status; 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 * Encode GETATTR request
*/ */
...@@ -3203,6 +3227,14 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_ ...@@ -3203,6 +3227,14 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_
return status; 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 * Decode GETATTR response
*/ */
...@@ -3793,6 +3825,7 @@ struct rpc_procinfo nfs4_procedures[] = { ...@@ -3793,6 +3825,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(REMOVE, enc_remove, dec_remove), PROC(REMOVE, enc_remove, dec_remove),
PROC(RENAME, enc_rename, dec_rename), PROC(RENAME, enc_rename, dec_rename),
PROC(LINK, enc_link, dec_link), PROC(LINK, enc_link, dec_link),
PROC(SYMLINK, enc_symlink, dec_symlink),
PROC(CREATE, enc_create, dec_create), PROC(CREATE, enc_create, dec_create),
PROC(PATHCONF, enc_pathconf, dec_pathconf), PROC(PATHCONF, enc_pathconf, dec_pathconf),
PROC(STATFS, enc_statfs, dec_statfs), PROC(STATFS, enc_statfs, dec_statfs),
......
...@@ -400,6 +400,8 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, ...@@ -400,6 +400,8 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
}; };
int status; int status;
if (path->len > NFS2_MAXPATHLEN)
return -ENAMETOOLONG;
dprintk("NFS call symlink %s -> %s\n", name->name, path->name); dprintk("NFS call symlink %s -> %s\n", name->name, path->name);
fattr->valid = 0; fattr->valid = 0;
status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0); status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#define NFS4_VERIFIER_SIZE 8 #define NFS4_VERIFIER_SIZE 8
#define NFS4_FHSIZE 128 #define NFS4_FHSIZE 128
#define NFS4_MAXPATHLEN PATH_MAX
#define NFS4_MAXNAMLEN NAME_MAX #define NFS4_MAXNAMLEN NAME_MAX
#define NFS4_ACCESS_READ 0x0001 #define NFS4_ACCESS_READ 0x0001
...@@ -372,6 +373,7 @@ enum { ...@@ -372,6 +373,7 @@ enum {
NFSPROC4_CLNT_REMOVE, NFSPROC4_CLNT_REMOVE,
NFSPROC4_CLNT_RENAME, NFSPROC4_CLNT_RENAME,
NFSPROC4_CLNT_LINK, NFSPROC4_CLNT_LINK,
NFSPROC4_CLNT_SYMLINK,
NFSPROC4_CLNT_CREATE, NFSPROC4_CLNT_CREATE,
NFSPROC4_CLNT_PATHCONF, NFSPROC4_CLNT_PATHCONF,
NFSPROC4_CLNT_STATFS, NFSPROC4_CLNT_STATFS,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment