Fri Jan 20 22:07:58 2012 UTC ()
Ensure psshfs_node_read() completely reads all data before return.
Fixes file corruption in psshfs exposed with kernel MAXPHYS at 128KiB.


(jakllsch)
diff -r1.63 -r1.64 src/usr.sbin/puffs/mount_psshfs/node.c

cvs diff -r1.63 -r1.64 src/usr.sbin/puffs/mount_psshfs/node.c (expand / switch to unified diff)

--- src/usr.sbin/puffs/mount_psshfs/node.c 2011/08/12 04:14:00 1.63
+++ src/usr.sbin/puffs/mount_psshfs/node.c 2012/01/20 22:07:58 1.64
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: node.c,v 1.63 2011/08/12 04:14:00 riastradh Exp $ */ 1/* $NetBSD: node.c,v 1.64 2012/01/20 22:07:58 jakllsch Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved. 4 * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
@@ -17,27 +17,27 @@ @@ -17,27 +17,27 @@
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE. 25 * SUCH DAMAGE.
26 */ 26 */
27 27
28#include <sys/cdefs.h> 28#include <sys/cdefs.h>
29#ifndef lint 29#ifndef lint
30__RCSID("$NetBSD: node.c,v 1.63 2011/08/12 04:14:00 riastradh Exp $"); 30__RCSID("$NetBSD: node.c,v 1.64 2012/01/20 22:07:58 jakllsch Exp $");
31#endif /* !lint */ 31#endif /* !lint */
32 32
33#include <assert.h> 33#include <assert.h>
34#include <errno.h> 34#include <errno.h>
35#include <stdio.h> 35#include <stdio.h>
36#include <stdlib.h> 36#include <stdlib.h>
37 37
38#include "psshfs.h" 38#include "psshfs.h"
39#include "sftp_proto.h" 39#include "sftp_proto.h"
40 40
41int 41int
42psshfs_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, 42psshfs_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc,
43 struct puffs_newinfo *pni, const struct puffs_cn *pcn) 43 struct puffs_newinfo *pni, const struct puffs_cn *pcn)
@@ -515,60 +515,70 @@ psshfs_node_read(struct puffs_usermount  @@ -515,60 +515,70 @@ psshfs_node_read(struct puffs_usermount
515 } 515 }
516 psn->stat &= ~PSN_LAZYWAIT_R; 516 psn->stat &= ~PSN_LAZYWAIT_R;
517 517
518 if ((rv = psn->lazyopen_err_r) != 0) 518 if ((rv = psn->lazyopen_err_r) != 0)
519 goto farout; 519 goto farout;
520 } 520 }
521 521
522 /* if there is still no handle, just refuse to live with this */ 522 /* if there is still no handle, just refuse to live with this */
523 if (!psn->fhand_r) { 523 if (!psn->fhand_r) {
524 rv = EINVAL; 524 rv = EINVAL;
525 goto farout; 525 goto farout;
526 } 526 }
527 527
 528again:
528 readlen = *resid; 529 readlen = *resid;
529 psbuf_req_data(pb, SSH_FXP_READ, reqid, psn->fhand_r, psn->fhand_r_len); 530 psbuf_req_data(pb, SSH_FXP_READ, reqid, psn->fhand_r, psn->fhand_r_len);
530 psbuf_put_8(pb, offset); 531 psbuf_put_8(pb, offset);
531 psbuf_put_4(pb, readlen); 532 psbuf_put_4(pb, readlen);
532 533
533 /* 534 /*
534 * Do this *after* accessing the file, the handle might not 535 * Do this *after* accessing the file, the handle might not
535 * exist after blocking. 536 * exist after blocking.
536 */ 537 */
537 if (max_reads && ++psn->readcount > max_reads) { 538 if (max_reads && ++psn->readcount > max_reads) {
538 struct psshfs_wait pw; 539 struct psshfs_wait pw;
539 540
540 pw.pw_cc = pcc; 541 pw.pw_cc = pcc;
541 pw.pw_type = PWTYPE_READ2; 542 pw.pw_type = PWTYPE_READ2;
542 TAILQ_INSERT_TAIL(&psn->pw, &pw, pw_entries); 543 TAILQ_INSERT_TAIL(&psn->pw, &pw, pw_entries);
543 puffs_cc_yield(pcc); 544 puffs_cc_yield(pcc);
544 } 545 }
545 546
546 GETRESPONSE(pb, pctx->sshfd_data); 547 GETRESPONSE(pb, pctx->sshfd_data);
547 548
548 rv = psbuf_do_data(pb, buf, &readlen); 549 rv = psbuf_do_data(pb, buf, &readlen);
549 if (rv == 0) 550 if (rv == 0) {
550 *resid -= readlen; 551 *resid -= readlen;
 552 buf += readlen;
 553 offset += readlen;
 554 }
551 555
552 out: 556 out:
553 if (max_reads && --psn->readcount >= max_reads) { 557 if (max_reads && --psn->readcount >= max_reads) {
554 TAILQ_FOREACH(pwp, &psn->pw, pw_entries) 558 TAILQ_FOREACH(pwp, &psn->pw, pw_entries)
555 if (pwp->pw_type == PWTYPE_READ2) 559 if (pwp->pw_type == PWTYPE_READ2)
556 break; 560 break;
557 assert(pwp != NULL); 561 assert(pwp != NULL);
558 puffs_cc_schedule(pwp->pw_cc); 562 puffs_cc_schedule(pwp->pw_cc);
559 TAILQ_REMOVE(&psn->pw, pwp, pw_entries); 563 TAILQ_REMOVE(&psn->pw, pwp, pw_entries);
560 } 564 }
561 565
 566 if (rv == 0 && *resid > 0) {
 567 reqid = NEXTREQ(pctx);
 568 psbuf_recycleout(pb);
 569 goto again;
 570 }
 571
562 farout: 572 farout:
563 /* check if we need a lazyclose */ 573 /* check if we need a lazyclose */
564 if (psn->stat & PSN_HANDLECLOSE && psn->fhand_r) { 574 if (psn->stat & PSN_HANDLECLOSE && psn->fhand_r) {
565 TAILQ_FOREACH(pwp, &psn->pw, pw_entries) 575 TAILQ_FOREACH(pwp, &psn->pw, pw_entries)
566 if (pwp->pw_type == PWTYPE_READ1) 576 if (pwp->pw_type == PWTYPE_READ1)
567 break; 577 break;
568 if (pwp == NULL) 578 if (pwp == NULL)
569 closehandles(pu, psn, HANDLE_READ); 579 closehandles(pu, psn, HANDLE_READ);
570 } 580 }
571 PSSHFSRETURN(rv); 581 PSSHFSRETURN(rv);
572} 582}
573 583
574/* XXX: we should getattr for size */ 584/* XXX: we should getattr for size */