geom_label: Add more validation for NTFS volume tasting

- Ensure that the computed MFT record size isn't negative or larger than
  maxphys before trying to read $Volume.
- Guard against truncated records in volume metadata.
- Ensure that the record length is large enough to contain the volume
  name.
- Verify that the (UTF-16-encoded) volume name's length is a multiple of
  two.

PR:		258833, 258914
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Mark Johnston 2021-10-04 17:48:44 -04:00
parent d43fa8ef53
commit f0a08fa9f5

View File

@ -99,7 +99,8 @@ g_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size)
struct ntfs_filerec *fr;
struct ntfs_attr *atr;
off_t voloff;
char *filerecp, *ap;
size_t recoff;
char *filerecp;
int8_t mftrecsz;
char vnchar;
int recsize, j;
@ -119,8 +120,9 @@ g_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size)
goto done;
mftrecsz = bf->bf_mftrecsz;
recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) : (1 << -mftrecsz);
if (recsize == 0 || recsize % pp->sectorsize != 0)
recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) :
(1 << -mftrecsz);
if (recsize <= 0 || recsize > maxphys || recsize % pp->sectorsize != 0)
goto done;
voloff = bf->bf_mftcn * bf->bf_spc * bf->bf_bps +
@ -132,24 +134,33 @@ g_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size)
if (filerecp == NULL)
goto done;
fr = (struct ntfs_filerec *)filerecp;
if (fr->fr_hdrmagic != NTFS_FILEMAGIC)
goto done;
for (ap = filerecp + fr->fr_attroff;
atr = (struct ntfs_attr *)ap, atr->a_type != -1;
ap += atr->reclen) {
for (recoff = fr->fr_attroff;
recoff <= recsize - 2 * sizeof(uint32_t);
recoff += atr->reclen) {
atr = (struct ntfs_attr *)(filerecp + recoff);
if (atr->a_type == -1)
break;
if (atr->reclen < sizeof(*atr))
break;
if (recsize - recoff < atr->reclen)
break;
if (atr->a_type == NTFS_A_VOLUMENAME) {
if(atr->a_datalen >= size *2){
label[0] = 0;
goto done;
}
if (atr->a_dataoff > atr->reclen ||
atr->a_datalen > atr->reclen - atr->a_dataoff)
break;
/*
*UNICODE to ASCII.
* UNICODE to ASCII.
* Should we need to use iconv(9)?
*/
if (atr->a_datalen >= size * 2 ||
atr->a_datalen % 2 != 0)
break;
for (j = 0; j < atr->a_datalen; j++) {
vnchar = *(ap + atr->a_dataoff + j);
vnchar = ((char *)atr)[atr->a_dataoff + j];
if (j & 1) {
if (vnchar) {
label[0] = 0;