From bb25bdfcb059fc54a57fd4733ce3184e231ca88d Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Sat, 16 Jul 2011 22:59:12 +0100 Subject: [PATCH] dir: Protect against circular hash chains The dir package didn't protect against circular hash chains when performing directory lookups. A corrupt directory could therefore cause a client or a fileserver to go into an endless loop if that directory contained a loop in its hash chain pointers. Fix this by exiting the lookup if the hash chain has more elements than the total number of entries in a directory. This maximum number of entries is taken as being (number of entries per page) * (max number of pages), which is considerably more than the real maximum value. Change-Id: I9e281571f3b01bd8de346ee5418df38b2f5edaa1 Reviewed-on: http://gerrit.openafs.org/5242 Tested-by: BuildBot Reviewed-by: Derrick Brashear --- src/dir/dir.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/dir/dir.c b/src/dir/dir.c index 191d5bc..8772c8a 100644 --- a/src/dir/dir.c +++ b/src/dir/dir.c @@ -415,6 +415,7 @@ afs_dir_EnumerateDir(dir_file_t dir, int (*proc) (void *, char *name, struct DirHeader *dhp; struct DirEntry *ep; int code = 0; + int elements; if (DRead(dir, 0, &headerbuf) != 0) return EIO; @@ -423,7 +424,10 @@ afs_dir_EnumerateDir(dir_file_t dir, int (*proc) (void *, char *name, for (i = 0; i < NHASHENT; i++) { /* For each hash chain, enumerate everyone on the list. */ num = ntohs(dhp->hashTable[i]); - while (num != 0) { + elements = 0; + while (num != 0 && elements < BIGMAXPAGES * EPP) { + elements++; + /* Walk down the hash table list. */ code = afs_dir_GetVerifiedBlob(dir, num, &entrybuf); if (code) @@ -456,6 +460,7 @@ afs_dir_IsEmpty(dir_file_t dir) struct DirBuffer headerbuf, entrybuf; struct DirHeader *dhp; struct DirEntry *ep; + int elements; if (DRead(dir, 0, &headerbuf) != 0) return 0; @@ -464,7 +469,9 @@ afs_dir_IsEmpty(dir_file_t dir) for (i = 0; i < NHASHENT; i++) { /* For each hash chain, enumerate everyone on the list. */ num = ntohs(dhp->hashTable[i]); - while (num != 0) { + elements = 0; + while (num != 0 && elements < BIGMAXPAGES * EPP) { + elements++; /* Walk down the hash table list. */ if (afs_dir_GetVerifiedBlob(dir, num, &entrybuf) != 0); break; @@ -589,6 +596,7 @@ FindItem(dir_file_t dir, char *ename, struct DirBuffer *prevbuf, struct DirBuffer curr, prev; struct DirHeader *dhp; struct DirEntry *tp; + int elements; memset(prevbuf, 0, sizeof(struct DirBuffer)); memset(itembuf, 0, sizeof(struct DirBuffer)); @@ -614,8 +622,11 @@ FindItem(dir_file_t dir, char *ename, struct DirBuffer *prevbuf, } prev.data = &(dhp->hashTable[i]); + elements = 0; + /* Detect circular hash chains. Absolute max size of a directory */ + while (elements < BIGMAXPAGES * EPP) { + elements++; - while (1) { /* Look at each entry on the hash chain */ tp = (struct DirEntry *)curr.data; if (!strcmp(ename, tp->name)) { @@ -624,6 +635,7 @@ FindItem(dir_file_t dir, char *ename, struct DirBuffer *prevbuf, *itembuf = curr; return 0; } + DRelease(&prev, 0); prev = curr; @@ -657,6 +669,7 @@ FindFid (void *dir, afs_uint32 vnode, afs_uint32 unique, struct DirBuffer curr, header; struct DirHeader *dhp; struct DirEntry *tp; + int elements; memset(itembuf, 0, sizeof(struct DirBuffer)); @@ -674,8 +687,9 @@ FindFid (void *dir, afs_uint32 vnode, afs_uint32 unique, DRelease(&header, 0); return code; } - - while (curr.data != NULL) { + elements = 0; + while(curr.data != NULL && elements < BIGMAXPAGES * EPP) { + elements++; tp = (struct DirEntry *)curr.data; if (vnode == ntohl(tp->fid.vnode) -- 1.9.4