Mon Jul 7 17:55:53 2014 UTC ()
From: http://marc.info/?l=openbsd-tech&m=140275150804337&w=2
Avoid infinite loops in cluster chain linked lists.


(christos)
diff -r1.25 -r1.26 src/sbin/fsck_msdos/fat.c

cvs diff -r1.25 -r1.26 src/sbin/fsck_msdos/fat.c (expand / switch to unified diff)

--- src/sbin/fsck_msdos/fat.c 2014/07/07 17:45:42 1.25
+++ src/sbin/fsck_msdos/fat.c 2014/07/07 17:55:53 1.26
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: fat.c,v 1.25 2014/07/07 17:45:42 christos Exp $ */ 1/* $NetBSD: fat.c,v 1.26 2014/07/07 17:55:53 christos Exp $ */
2 2
3/* 3/*
4 * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank 4 * Copyright (C) 1995, 1996, 1997 Wolfgang Solfrank
5 * Copyright (c) 1995 Martin Husemann 5 * Copyright (c) 1995 Martin Husemann
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -18,27 +18,27 @@ @@ -18,27 +18,27 @@
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28 28
29#include <sys/cdefs.h> 29#include <sys/cdefs.h>
30#ifndef lint 30#ifndef lint
31__RCSID("$NetBSD: fat.c,v 1.25 2014/07/07 17:45:42 christos Exp $"); 31__RCSID("$NetBSD: fat.c,v 1.26 2014/07/07 17:55:53 christos Exp $");
32#endif /* not lint */ 32#endif /* not lint */
33 33
34#include <stdlib.h> 34#include <stdlib.h>
35#include <string.h> 35#include <string.h>
36#include <ctype.h> 36#include <ctype.h>
37#include <stdio.h> 37#include <stdio.h>
38#include <unistd.h> 38#include <unistd.h>
39 39
40#include "ext.h" 40#include "ext.h"
41#include "fsutil.h" 41#include "fsutil.h"
42 42
43static int checkclnum(struct bootblock *, u_int, cl_t, cl_t *); 43static int checkclnum(struct bootblock *, u_int, cl_t, cl_t *);
44static int clustdiffer(cl_t, cl_t *, cl_t *, u_int); 44static int clustdiffer(cl_t, cl_t *, cl_t *, u_int);
@@ -403,45 +403,51 @@ checkfat(struct bootblock *boot, struct  @@ -403,45 +403,51 @@ checkfat(struct bootblock *boot, struct
403 } 403 }
404 404
405 /* 405 /*
406 * pass 2: check for crosslinked chains (we couldn't do this in pass 1 because 406 * pass 2: check for crosslinked chains (we couldn't do this in pass 1 because
407 * we didn't know the real start of the chain then - would have treated partial 407 * we didn't know the real start of the chain then - would have treated partial
408 * chains as interlinked with their main chain) 408 * chains as interlinked with their main chain)
409 */ 409 */
410 for (head = CLUST_FIRST; head < boot->NumClusters; head++) { 410 for (head = CLUST_FIRST; head < boot->NumClusters; head++) {
411 /* find next untravelled chain */ 411 /* find next untravelled chain */
412 if (fat[head].head != head) 412 if (fat[head].head != head)
413 continue; 413 continue;
414 414
415 /* follow the chain to its end (hopefully) */ 415 /* follow the chain to its end (hopefully) */
416 for (p = head; 416 for (len = fat[head].length, p = head;
417 (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters; 417 (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters;
418 p = n) 418 p = n)
419 if (fat[n].head != head) 419 if (fat[n].head != head || len-- < 2)
420 break; 420 break;
421 if (n >= CLUST_EOFS) 421 if (n >= CLUST_EOFS)
422 continue; 422 continue;
423 423
424 if (n == CLUST_FREE || n >= CLUST_RSRVD) { 424 if (n == CLUST_FREE || n >= CLUST_RSRVD) {
425 pwarn("Cluster chain starting at %u ends with cluster marked %s\n", 425 pwarn("Cluster chain starting at %u ends with cluster marked %s\n",
426 head, rsrvdcltype(n)); 426 head, rsrvdcltype(n));
 427clear:
427 ret |= tryclear(boot, fat, head, &fat[p].next); 428 ret |= tryclear(boot, fat, head, &fat[p].next);
428 continue; 429 continue;
429 } 430 }
430 if (n < CLUST_FIRST || n >= boot->NumClusters) { 431 if (n < CLUST_FIRST || n >= boot->NumClusters) {
431 pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n", 432 pwarn("Cluster chain starting at %u ends with cluster out of range (%u)\n",
432 head, n); 433 head, n);
433 ret |= tryclear(boot, fat, head, &fat[p].next); 434 goto clear;
434 continue; 435 }
 436 if (head == fat[n].head) {
 437 pwarn("Cluster chain starting at %u loops at cluster %u\n",
 438
 439 head, p);
 440 goto clear;
435 } 441 }
436 pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n", 442 pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n",
437 head, fat[n].head, n); 443 head, fat[n].head, n);
438 conf = tryclear(boot, fat, head, &fat[p].next); 444 conf = tryclear(boot, fat, head, &fat[p].next);
439 if (ask(0, "Clear chain starting at %u", h = fat[n].head)) { 445 if (ask(0, "Clear chain starting at %u", h = fat[n].head)) {
440 if (conf == FSERROR) { 446 if (conf == FSERROR) {
441 /* 447 /*
442 * Transfer the common chain to the one not cleared above. 448 * Transfer the common chain to the one not cleared above.
443 */ 449 */
444 for (p = n; 450 for (p = n;
445 p >= CLUST_FIRST && p < boot->NumClusters; 451 p >= CLUST_FIRST && p < boot->NumClusters;
446 p = fat[p].next) { 452 p = fat[p].next) {
447 if (h != fat[p].head) { 453 if (h != fat[p].head) {