Implement checking of .' and
..' entries of subdirectory.
Reviewed by: pfg
Obtained from: Android b6ee08aadb
%5E%21/
MFC after: 2 weeks
Differential Revision: https://reviews.freebsd.org/D19824
This commit is contained in:
parent
bcf55f6463
commit
d78b6f1ee8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=345900
@ -444,6 +444,77 @@ checksize(struct bootblock *boot, struct fatEntry *fat, u_char *p,
|
|||||||
return FSOK;
|
return FSOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const u_char dot_name[] = {
|
||||||
|
'.', ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
|
||||||
|
static const u_char dotdot_name[] = {
|
||||||
|
'.', '.',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic sanity check if the subdirectory have good '.' and '..' entries,
|
||||||
|
* and they are directory entries. Further sanity checks are performed
|
||||||
|
* when we traverse into it.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
check_subdirectory(int f, struct bootblock *boot, struct dosDirEntry *dir)
|
||||||
|
{
|
||||||
|
u_char *buf, *cp;
|
||||||
|
off_t off;
|
||||||
|
cl_t cl;
|
||||||
|
int retval = FSOK;
|
||||||
|
|
||||||
|
cl = dir->head;
|
||||||
|
if (dir->parent && (cl < CLUST_FIRST || cl >= boot->NumClusters)) {
|
||||||
|
return FSERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(boot->flags & FAT32) && !dir->parent) {
|
||||||
|
off = boot->bpbResSectors + boot->bpbFATs *
|
||||||
|
boot->FATsecs;
|
||||||
|
} else {
|
||||||
|
off = cl * boot->bpbSecPerClust + boot->ClusterOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only need to check the first two entries of the directory,
|
||||||
|
* which is found in the first sector of the directory entry,
|
||||||
|
* so read in only the first sector.
|
||||||
|
*/
|
||||||
|
buf = malloc(boot->bpbBytesPerSec);
|
||||||
|
if (buf == NULL) {
|
||||||
|
perr("No space for directory buffer (%u)",
|
||||||
|
boot->bpbBytesPerSec);
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
off *= boot->bpbBytesPerSec;
|
||||||
|
if (lseek(f, off, SEEK_SET) != off ||
|
||||||
|
read(f, buf, boot->bpbBytesPerSec) != boot->bpbBytesPerSec) {
|
||||||
|
perr("Unable to read directory");
|
||||||
|
free(buf);
|
||||||
|
return FSFATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Both `.' and `..' must be present and be the first two entries
|
||||||
|
* and be ATTR_DIRECTORY of a valid subdirectory.
|
||||||
|
*/
|
||||||
|
cp = buf;
|
||||||
|
if (memcmp(cp, dot_name, sizeof(dot_name)) != 0 ||
|
||||||
|
(cp[11] & ATTR_DIRECTORY) != ATTR_DIRECTORY) {
|
||||||
|
pwarn("%s: Incorrect `.' for %s.\n", __func__, dir->name);
|
||||||
|
retval |= FSERROR;
|
||||||
|
}
|
||||||
|
cp += 32;
|
||||||
|
if (memcmp(cp, dotdot_name, sizeof(dotdot_name)) != 0 ||
|
||||||
|
(cp[11] & ATTR_DIRECTORY) != ATTR_DIRECTORY) {
|
||||||
|
pwarn("%s: Incorrect `..' for %s. \n", __func__, dir->name);
|
||||||
|
retval |= FSERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a directory and
|
* Read a directory and
|
||||||
* - resolve long name records
|
* - resolve long name records
|
||||||
@ -491,9 +562,6 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
|
|||||||
return FSFATAL;
|
return FSFATAL;
|
||||||
}
|
}
|
||||||
last /= 32;
|
last /= 32;
|
||||||
/*
|
|
||||||
* Check `.' and `..' entries here? XXX
|
|
||||||
*/
|
|
||||||
for (p = buffer, i = 0; i < last; i++, p += 32) {
|
for (p = buffer, i = 0; i < last; i++, p += 32) {
|
||||||
if (dir->fsckflags & DIREMPWARN) {
|
if (dir->fsckflags & DIREMPWARN) {
|
||||||
*p = SLOT_EMPTY;
|
*p = SLOT_EMPTY;
|
||||||
@ -830,6 +898,36 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Only one directory entry can point
|
||||||
|
* to dir->head, it's '.'.
|
||||||
|
*/
|
||||||
|
if (dirent.head == dir->head) {
|
||||||
|
pwarn("%s entry in %s has incorrect start cluster\n",
|
||||||
|
dirent.name, fullpath(dir));
|
||||||
|
if (ask(1, "Remove")) {
|
||||||
|
*p = SLOT_DELETED;
|
||||||
|
mod |= THISMOD|FSDIRMOD;
|
||||||
|
} else
|
||||||
|
mod |= FSERROR;
|
||||||
|
continue;
|
||||||
|
} else if ((check_subdirectory(f, boot,
|
||||||
|
&dirent) & FSERROR) == FSERROR) {
|
||||||
|
/*
|
||||||
|
* A subdirectory should have
|
||||||
|
* a dot (.) entry and a dot-dot
|
||||||
|
* (..) entry of ATTR_DIRECTORY,
|
||||||
|
* we will inspect further when
|
||||||
|
* traversing into it.
|
||||||
|
*/
|
||||||
|
if (ask(1, "Remove")) {
|
||||||
|
*p = SLOT_DELETED;
|
||||||
|
mod |= THISMOD|FSDIRMOD;
|
||||||
|
} else
|
||||||
|
mod |= FSERROR;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create directory tree node */
|
/* create directory tree node */
|
||||||
|
Loading…
Reference in New Issue
Block a user