diff options
author | Tobias Stoeckmann <tobias@cvs.openbsd.org> | 2014-06-14 19:32:26 +0000 |
---|---|---|
committer | Tobias Stoeckmann <tobias@cvs.openbsd.org> | 2014-06-14 19:32:26 +0000 |
commit | 321435a0d7839129d214171ffae5b703308b535e (patch) | |
tree | b3442fadfb720505e9e0cc3e2b2c937a998b21fa /sbin | |
parent | 9a98ef3eab2c8772ca49e2c4a5ad66b6502ede13 (diff) |
Avoid infinite loop if cluster chain is a cyclic list.
Inspired by Android's commit b6ee08aadb580341a4d80943741b80de16a88b5d,
but fixing the actually offending cluster, not a random one.
ok krw@
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/fsck_msdos/fat.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/sbin/fsck_msdos/fat.c b/sbin/fsck_msdos/fat.c index 701e7cc1efd..f6233ceaa24 100644 --- a/sbin/fsck_msdos/fat.c +++ b/sbin/fsck_msdos/fat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fat.c,v 1.21 2014/06/14 12:33:07 tobias Exp $ */ +/* $OpenBSD: fat.c,v 1.22 2014/06/14 19:32:25 tobias Exp $ */ /* $NetBSD: fat.c,v 1.8 1997/10/17 11:19:53 ws Exp $ */ /* @@ -364,11 +364,13 @@ checkfat(struct bootblock *boot, struct fatEntry *fat) continue; /* follow the chain to its end (hopefully) */ - for (p = head; + for (len = fat[head].length, p = head; (n = fat[p].next) >= CLUST_FIRST && n < boot->NumClusters; - p = n) - if (fat[n].head != head) + p = n) { + /* len is always off by one due to n assignment */ + if (fat[n].head != head || len-- < 2) break; + } if (n >= CLUST_EOFS) continue; @@ -384,6 +386,12 @@ checkfat(struct bootblock *boot, struct fatEntry *fat) ret |= tryclear(boot, fat, head, &fat[p].next); continue; } + if (head == fat[n].head) { + pwarn("Cluster chain starting at %u loops at cluster %u\n", + head, p); + ret |= tryclear(boot, fat, head, &fat[p].next); + continue; + } pwarn("Cluster chains starting at %u and %u are linked at cluster %u\n", head, fat[n].head, n); conf = tryclear(boot, fat, head, &fat[p].next); |