diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 48 | ||||
-rw-r--r-- | fs/nfsd/nfsxdr.c | 46 |
2 files changed, 77 insertions, 17 deletions
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 7e4bb0af24d7..43fb360784b7 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -369,7 +369,7 @@ int | |||
369 | nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | 369 | nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, |
370 | struct nfsd3_writeargs *args) | 370 | struct nfsd3_writeargs *args) |
371 | { | 371 | { |
372 | unsigned int len, v, hdr; | 372 | unsigned int len, v, hdr, dlen; |
373 | u32 max_blocksize = svc_max_payload(rqstp); | 373 | u32 max_blocksize = svc_max_payload(rqstp); |
374 | 374 | ||
375 | if (!(p = decode_fh(p, &args->fh)) | 375 | if (!(p = decode_fh(p, &args->fh)) |
@@ -379,18 +379,47 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
379 | args->count = ntohl(*p++); | 379 | args->count = ntohl(*p++); |
380 | args->stable = ntohl(*p++); | 380 | args->stable = ntohl(*p++); |
381 | len = args->len = ntohl(*p++); | 381 | len = args->len = ntohl(*p++); |
382 | /* | ||
383 | * The count must equal the amount of data passed. | ||
384 | */ | ||
385 | if (args->count != args->len) | ||
386 | return 0; | ||
382 | 387 | ||
388 | /* | ||
389 | * Check to make sure that we got the right number of | ||
390 | * bytes. | ||
391 | * | ||
392 | * If more than one page was used, then compute the length | ||
393 | * of the data in the request as the total size of the | ||
394 | * request minus the transport protocol headers minus the | ||
395 | * RPC protocol headers minus the NFS protocol fields | ||
396 | * already consumed. If the request fits into a single | ||
397 | * page, then compete the length of the data as the size | ||
398 | * of the NFS portion of the request minus the NFS | ||
399 | * protocol fields already consumed. | ||
400 | */ | ||
383 | hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; | 401 | hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; |
384 | if (rqstp->rq_arg.len < hdr || | 402 | if (rqstp->rq_respages != rqstp->rq_pages + 1) { |
385 | rqstp->rq_arg.len - hdr < len) | 403 | dlen = rqstp->rq_arg.len - |
404 | (PAGE_SIZE - rqstp->rq_arg.head[0].iov_len) - hdr; | ||
405 | } else { | ||
406 | dlen = rqstp->rq_arg.head[0].iov_len - hdr; | ||
407 | } | ||
408 | /* | ||
409 | * Round the length of the data which was specified up to | ||
410 | * the next multiple of XDR units and then compare that | ||
411 | * against the length which was actually received. | ||
412 | */ | ||
413 | if (dlen != ((len + 3) & ~0x3)) | ||
386 | return 0; | 414 | return 0; |
387 | 415 | ||
416 | if (args->count > max_blocksize) { | ||
417 | args->count = max_blocksize; | ||
418 | len = args->len = max_blocksize; | ||
419 | } | ||
388 | rqstp->rq_vec[0].iov_base = (void*)p; | 420 | rqstp->rq_vec[0].iov_base = (void*)p; |
389 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; | 421 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; |
390 | 422 | v = 0; | |
391 | if (len > max_blocksize) | ||
392 | len = max_blocksize; | ||
393 | v= 0; | ||
394 | while (len > rqstp->rq_vec[v].iov_len) { | 423 | while (len > rqstp->rq_vec[v].iov_len) { |
395 | len -= rqstp->rq_vec[v].iov_len; | 424 | len -= rqstp->rq_vec[v].iov_len; |
396 | v++; | 425 | v++; |
@@ -398,9 +427,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
398 | rqstp->rq_vec[v].iov_len = PAGE_SIZE; | 427 | rqstp->rq_vec[v].iov_len = PAGE_SIZE; |
399 | } | 428 | } |
400 | rqstp->rq_vec[v].iov_len = len; | 429 | rqstp->rq_vec[v].iov_len = len; |
401 | args->vlen = v+1; | 430 | args->vlen = v + 1; |
402 | 431 | return 1; | |
403 | return args->count == args->len && rqstp->rq_vec[0].iov_len > 0; | ||
404 | } | 432 | } |
405 | 433 | ||
406 | int | 434 | int |
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 0c24b9e24fe8..6035e03655c6 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
@@ -284,8 +284,9 @@ int | |||
284 | nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | 284 | nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, |
285 | struct nfsd_writeargs *args) | 285 | struct nfsd_writeargs *args) |
286 | { | 286 | { |
287 | unsigned int len; | 287 | unsigned int len, hdr, dlen; |
288 | int v; | 288 | int v; |
289 | |||
289 | if (!(p = decode_fh(p, &args->fh))) | 290 | if (!(p = decode_fh(p, &args->fh))) |
290 | return 0; | 291 | return 0; |
291 | 292 | ||
@@ -293,11 +294,42 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
293 | args->offset = ntohl(*p++); /* offset */ | 294 | args->offset = ntohl(*p++); /* offset */ |
294 | p++; /* totalcount */ | 295 | p++; /* totalcount */ |
295 | len = args->len = ntohl(*p++); | 296 | len = args->len = ntohl(*p++); |
296 | rqstp->rq_vec[0].iov_base = (void*)p; | 297 | /* |
297 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - | 298 | * The protocol specifies a maximum of 8192 bytes. |
298 | (((void*)p) - rqstp->rq_arg.head[0].iov_base); | 299 | */ |
299 | if (len > NFSSVC_MAXBLKSIZE_V2) | 300 | if (len > NFSSVC_MAXBLKSIZE_V2) |
300 | len = NFSSVC_MAXBLKSIZE_V2; | 301 | return 0; |
302 | |||
303 | /* | ||
304 | * Check to make sure that we got the right number of | ||
305 | * bytes. | ||
306 | * | ||
307 | * If more than one page was used, then compute the length | ||
308 | * of the data in the request as the total size of the | ||
309 | * request minus the transport protocol headers minus the | ||
310 | * RPC protocol headers minus the NFS protocol fields | ||
311 | * already consumed. If the request fits into a single | ||
312 | * page, then compete the length of the data as the size | ||
313 | * of the NFS portion of the request minus the NFS | ||
314 | * protocol fields already consumed. | ||
315 | */ | ||
316 | hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; | ||
317 | if (rqstp->rq_respages != rqstp->rq_pages + 1) { | ||
318 | dlen = rqstp->rq_arg.len - | ||
319 | (PAGE_SIZE - rqstp->rq_arg.head[0].iov_len) - hdr; | ||
320 | } else { | ||
321 | dlen = rqstp->rq_arg.head[0].iov_len - hdr; | ||
322 | } | ||
323 | /* | ||
324 | * Round the length of the data which was specified up to | ||
325 | * the next multiple of XDR units and then compare that | ||
326 | * against the length which was actually received. | ||
327 | */ | ||
328 | if (dlen != ((len + 3) & ~0x3)) | ||
329 | return 0; | ||
330 | |||
331 | rqstp->rq_vec[0].iov_base = (void*)p; | ||
332 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; | ||
301 | v = 0; | 333 | v = 0; |
302 | while (len > rqstp->rq_vec[v].iov_len) { | 334 | while (len > rqstp->rq_vec[v].iov_len) { |
303 | len -= rqstp->rq_vec[v].iov_len; | 335 | len -= rqstp->rq_vec[v].iov_len; |
@@ -306,8 +338,8 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
306 | rqstp->rq_vec[v].iov_len = PAGE_SIZE; | 338 | rqstp->rq_vec[v].iov_len = PAGE_SIZE; |
307 | } | 339 | } |
308 | rqstp->rq_vec[v].iov_len = len; | 340 | rqstp->rq_vec[v].iov_len = len; |
309 | args->vlen = v+1; | 341 | args->vlen = v + 1; |
310 | return rqstp->rq_vec[0].iov_len > 0; | 342 | return 1; |
311 | } | 343 | } |
312 | 344 | ||
313 | int | 345 | int |