Avoid misaligned access in disklabel(8) in find_label()

Introduce a new helper variable tlp and use it for memory access.

Detected with MKSANITIZER/UBSan

A patch by <christos>
This commit is contained in:
kamil 2018-06-27 01:14:48 +00:00
parent 2e33b73cf0
commit bd8efe16d3

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.49 2018/04/01 04:35:02 ryo Exp $ */
/* $NetBSD: main.c,v 1.50 2018/06/27 01:14:48 kamil Exp $ */
/*
* Copyright (c) 2006 The NetBSD Foundation, Inc.
@ -76,7 +76,7 @@ __COPYRIGHT("@(#) Copyright (c) 1987, 1993\
static char sccsid[] = "@(#)disklabel.c 8.4 (Berkeley) 5/4/95";
/* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */
#else
__RCSID("$NetBSD: main.c,v 1.49 2018/04/01 04:35:02 ryo Exp $");
__RCSID("$NetBSD: main.c,v 1.50 2018/06/27 01:14:48 kamil Exp $");
#endif
#endif /* not lint */
@ -1189,7 +1189,7 @@ readlabel(int f)
static struct disklabel *
find_label(int f, u_int sector)
{
struct disklabel *disk_lp, hlp;
struct disklabel *disk_lp, hlp, tlp;
int i;
off_t offset;
const char *is_deleted;
@ -1209,30 +1209,31 @@ find_label(int f, u_int sector)
/* Check expected offset first */
for (offset = LABEL_OFFSET, i = -4;; offset = i += 4) {
is_deleted = "";
disk_lp = (void *)(bootarea + offset);
if (i == LABEL_OFFSET)
continue;
disk_lp = (void *)(bootarea + offset);
memcpy(&tlp, disk_lp, sizeof(tlp));
if ((char *)(disk_lp + 1) > bootarea + bootarea_len)
break;
if (disk_lp->d_magic2 != disk_lp->d_magic)
if (tlp.d_magic2 != tlp.d_magic)
continue;
if (read_all && (disk_lp->d_magic == DISKMAGIC_DELETED ||
disk_lp->d_magic == DISKMAGIC_DELETED_REV)) {
disk_lp->d_magic ^= ~0u;
disk_lp->d_magic2 ^= ~0u;
if (read_all && (tlp.d_magic == DISKMAGIC_DELETED ||
tlp.d_magic == DISKMAGIC_DELETED_REV)) {
tlp.d_magic ^= ~0u;
tlp.d_magic2 ^= ~0u;
is_deleted = "deleted ";
}
if (target32toh(disk_lp->d_magic) != DISKMAGIC) {
if (target32toh(tlp.d_magic) != DISKMAGIC) {
/* XXX: Do something about byte-swapped labels ? */
if (target32toh(disk_lp->d_magic) == DISKMAGIC_REV &&
target32toh(disk_lp->d_magic2) == DISKMAGIC_REV)
if (target32toh(tlp.d_magic) == DISKMAGIC_REV &&
target32toh(tlp.d_magic2) == DISKMAGIC_REV)
warnx("ignoring %sbyteswapped label"
" at offset %jd from sector %u",
is_deleted, (intmax_t)offset, sector);
continue;
}
if (target16toh(disk_lp->d_npartitions) > maxpartitions ||
dkcksum_target(disk_lp) != 0) {
if (target16toh(tlp.d_npartitions) > maxpartitions ||
dkcksum_target(&tlp) != 0) {
if (verbose > 0)
warnx("corrupt label found at offset %jd in "
"sector %u", (intmax_t)offset, sector);
@ -1246,7 +1247,7 @@ find_label(int f, u_int sector)
/* To print all the labels we have to do it here */
/* XXX: maybe we should compare them? */
targettohlabel(&hlp, disk_lp);
targettohlabel(&hlp, &tlp);
printf("# %ssector %u offset %jd bytes\n",
is_deleted, sector, (intmax_t)offset);
if (tflag)
@ -1256,7 +1257,8 @@ find_label(int f, u_int sector)
showpartitions(stdout, &hlp, Cflag);
}
checklabel(&hlp);
htotargetlabel(disk_lp, &hlp);
htotargetlabel(&tlp, &hlp);
memcpy(disk_lp, &tlp, sizeof(tlp));
/* Remember we've found a label */
read_all = 2;
}