#ifdef KERNEL
# if !defined(UKERNEL)
# include "h/types.h"
-# include "h/param.h"
+# if !defined(AFS_LINUX26_ENV)
+# include "h/param.h"
+# endif
# ifdef AFS_AUX_ENV
# include "h/mmu.h"
# include "h/seg.h"
# include "h/kernel.h"
# endif
# endif
-# if defined(AFS_SUN56_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_DARWIN80_ENV)
+# if defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_DARWIN80_ENV)
# include "afs/sysincludes.h"
# endif
# if !defined(AFS_SGI64_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_OBSD48_ENV) && !defined(AFS_NBSD_ENV)
DRelease(&prevbuf, 1);
index = DVOffset(&entrybuf) / 32;
nitems = afs_dir_NameBlobs(firstitem->name);
- DRelease(&entrybuf, 0);
+ /* Clear entire DirEntry and any DirXEntry extensions */
+ memset(firstitem, 0, nitems * sizeof(*firstitem));
+ DRelease(&entrybuf, 1);
FreeBlobs(dir, index, nitems);
return 0;
}
/* read the page in. */
if (DRead(dir, i, &pagebuf) != 0) {
- DRelease(&headerbuf, 1);
break;
}
pp = (struct PageHeader *)pagebuf.data;
struct DirHeader *dhp;
struct DirEntry *ep;
int code = 0;
+ int elements;
if (DRead(dir, 0, &headerbuf) != 0)
return EIO;
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. */
- DErrno = 0;
- if (afs_dir_GetBlob(dir, num, &entrybuf) != 0) {
- if (DErrno) {
- /* we failed, return why */
- DRelease(&headerbuf, 0);
- return DErrno;
- }
+ code = afs_dir_GetVerifiedBlob(dir, num, &entrybuf);
+ if (code)
+ goto out;
+
+ ep = (struct DirEntry *)entrybuf.data;
+ if (!ep) {
+ DRelease(&entrybuf, 0);
break;
}
- ep = (struct DirEntry *)entrybuf.data;
num = ntohs(ep->next);
code = (*proc) (hook, ep->name, ntohl(ep->fid.vnode),
ntohl(ep->fid.vunique));
DRelease(&entrybuf, 0);
if (code)
- break;
+ goto out;
}
}
+
+out:
DRelease(&headerbuf, 0);
return 0;
}
struct DirBuffer headerbuf, entrybuf;
struct DirHeader *dhp;
struct DirEntry *ep;
+ int elements;
if (DRead(dir, 0, &headerbuf) != 0)
return 0;
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_GetBlob(dir, num, &entrybuf) != 0);
+ if (afs_dir_GetVerifiedBlob(dir, num, &entrybuf) != 0)
break;
ep = (struct DirEntry *)entrybuf.data;
if (strcmp(ep->name, "..") && strcmp(ep->name, ".")) {
return 0;
}
-int
-afs_dir_GetBlob(dir_file_t dir, afs_int32 blobno, struct DirBuffer *buffer)
+/* Return a pointer to an entry, given its number. Also return the maximum
+ * size of the entry, which is determined by its position within the directory
+ * page.
+ */
+
+static int
+GetBlobWithLimit(dir_file_t dir, afs_int32 blobno,
+ struct DirBuffer *buffer, afs_size_t *maxlen)
{
+ afs_size_t pos;
int code;
+ *maxlen = 0;
memset(buffer, 0, sizeof(struct DirBuffer));
code = DRead(dir, blobno >> LEPP, buffer);
if (code)
return code;
- buffer->data = (void *)(((long)buffer->data) + 32 * (blobno & (EPP - 1)));
+ pos = 32 * (blobno & (EPP - 1));
+
+ *maxlen = AFS_PAGESIZE - pos - 1;
+
+ buffer->data = (void *)(((char *)buffer->data) + pos);
return 0;
}
+/* Given an entries number, return a pointer to that entry */
+int
+afs_dir_GetBlob(dir_file_t dir, afs_int32 blobno, struct DirBuffer *buffer)
+{
+ afs_size_t maxlen = 0;
+ return GetBlobWithLimit(dir, blobno, buffer, &maxlen);
+}
+
+/* Return an entry, having verified that the name held within the entry
+ * doesn't overflow off the end of the directory page it is contained
+ * within
+ */
+
+int
+afs_dir_GetVerifiedBlob(dir_file_t file, afs_int32 blobno,
+ struct DirBuffer *outbuf)
+{
+ struct DirEntry *dir;
+ struct DirBuffer buffer;
+ afs_size_t maxlen;
+ int code;
+ char *cp;
+
+ code = GetBlobWithLimit(file, blobno, &buffer, &maxlen);
+ if (code)
+ return code;
+
+ dir = (struct DirEntry *)buffer.data;
+
+ /* A blob is only valid if the name within it is NULL terminated before
+ * the end of the blob's containing page */
+ for (cp = dir->name; *cp != '\0' && cp < ((char *)dir) + maxlen; cp++);
+
+ if (*cp != '\0') {
+ DRelease(&buffer, 0);
+ return EIO;
+ }
+
+ *outbuf = buffer;
+ return 0;
+}
+
int
afs_dir_DirHash(char *string)
{
tval = hval & (NHASHENT - 1);
if (tval == 0)
return tval;
- else if (hval >= 1<<31)
+ else if (hval >= 1u<<31)
tval = NHASHENT - tval;
return tval;
}
struct DirBuffer curr, prev;
struct DirHeader *dhp;
struct DirEntry *tp;
+ int elements;
memset(prevbuf, 0, sizeof(struct DirBuffer));
memset(itembuf, 0, sizeof(struct DirBuffer));
return ENOENT;
}
- code = afs_dir_GetBlob(dir, (u_short) ntohs(dhp->hashTable[i]),
- &curr);
+ code = afs_dir_GetVerifiedBlob(dir,
+ (u_short) ntohs(dhp->hashTable[i]),
+ &curr);
if (code) {
DRelease(&prev, 0);
return code;
}
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)) {
*itembuf = curr;
return 0;
}
+
DRelease(&prev, 0);
- if (tp->next == 0) {
- /* The end of the line */
- DRelease(&curr, 0);
- return ENOENT;
- }
prev = curr;
prev.data = &(tp->next);
- code = afs_dir_GetBlob(dir, (u_short) ntohs(tp->next), &curr);
- if (code) {
- DRelease(&prev, 0);
- return code;
- }
+ if (tp->next == 0)
+ goto out; /* The end of the line */
+
+ code = afs_dir_GetVerifiedBlob(dir, (u_short) ntohs(tp->next),
+ &curr);
+ if (code)
+ goto out;
}
- /* Never reached */
+
+out:
+ DRelease(&prev, 0);
+ return ENOENT;
}
static int
struct DirBuffer curr, header;
struct DirHeader *dhp;
struct DirEntry *tp;
+ int elements;
memset(itembuf, 0, sizeof(struct DirBuffer));
for (i=0; i<NHASHENT; i++) {
if (dhp->hashTable[i] != 0) {
- code = afs_dir_GetBlob(dir, (u_short)ntohs(dhp->hashTable[i]),
- &curr);
+ code = afs_dir_GetVerifiedBlob(dir,
+ (u_short)ntohs(dhp->hashTable[i]),
+ &curr);
if (code) {
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)
if (next == 0)
break;
- code = afs_dir_GetBlob(dir, (u_short)ntohs(next), &curr);
+ code = afs_dir_GetVerifiedBlob(dir, (u_short)ntohs(next),
+ &curr);
if (code) {
DRelease(&header, 0);
return code;