summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2013-09-29 12:18:00 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2013-09-29 12:18:00 +0000
commite53736a186de0d3753163ca3b73fdbdd8e396faa (patch)
tree77970878a9a21d38c5a4f68498489c42f4cde514 /sys/arch
parent18cc517ab84a607582f90604f980de291f8a88c5 (diff)
Perform more consistency checks when walking the VDIT.
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/aviion/aviion/disksubr.c64
-rw-r--r--sys/arch/aviion/include/disklabel.h4
2 files changed, 54 insertions, 14 deletions
diff --git a/sys/arch/aviion/aviion/disksubr.c b/sys/arch/aviion/aviion/disksubr.c
index f31f24dbc8c..84458d2a459 100644
--- a/sys/arch/aviion/aviion/disksubr.c
+++ b/sys/arch/aviion/aviion/disksubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: disksubr.c,v 1.52 2013/09/28 19:25:24 miod Exp $ */
+/* $OpenBSD: disksubr.c,v 1.53 2013/09/29 12:17:59 miod Exp $ */
/*
* Copyright (c) 2013 Miodrag Vallat.
@@ -52,7 +52,8 @@
#include <sys/disk.h>
#include <sys/malloc.h>
-char *extract_vdit_portion(char *, const char *, unsigned int, int);
+char *extract_vdit_portion(char *, const char *, unsigned int, unsigned int,
+ int);
int readvditlabel(struct buf *, void (*)(struct buf *), struct disklabel *,
int *, int);
@@ -74,7 +75,6 @@ readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
if ((error = initdisklabel(lp)))
goto done;
- /* get a buffer and initialize it */
bp = geteblk((int)lp->d_secsize);
bp->b_dev = dev;
@@ -167,10 +167,12 @@ readvditlabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp,
{
struct buf *sbp = NULL;
struct vdm_label *vdl;
+ struct vdm_boot_info *vbi;
struct vdit_block_header *vbh;
struct vdit_entry_header *veh;
char *vdit_storage = NULL, *vdit_end;
- size_t vdit_size, largest_chunk;
+ size_t vdit_size;
+ unsigned int largest_chunk, vdit_blkno;
int expected_kind;
daddr_t blkno;
int error = 0;
@@ -198,13 +200,28 @@ readvditlabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp,
return EINVAL;
/*
+ * If the disk is a bootable disk, remember the boot block area, to
+ * be able to check that the VDIT does not overwrite it.
+ */
+
+ vbi = (struct vdm_boot_info *)(bp->b_data + dbtob(1) - sizeof *vbi);
+ if (vbi->signature != VDM_LABEL_SIGNATURE || vbi->boot_start == 0)
+ vbi = NULL;
+
+ if (vbi != NULL && vbi->boot_start == VDIT_SECTOR)
+ return EINVAL;
+
+ if (vbi != NULL && vbi->boot_start + vbi->boot_size < DL_GETBSTART(lp))
+ DL_SETBSTART(lp, vbi->boot_start + vbi->boot_size);
+
+ /*
* Figure out the size of the first VDIT.
*/
vdit_size = largest_chunk = 0;
expected_kind = VDIT_BLOCK_HEAD_BE;
blkno = VDIT_SECTOR;
- do {
+ for (;;) {
bp->b_blkno = blkno;
bp->b_bcount = lp->d_secsize;
CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
@@ -214,15 +231,30 @@ readvditlabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp,
return error;
vbh = (struct vdit_block_header *)bp->b_data;
- if (VDM_ID_KIND(&vbh->id) != expected_kind)
+ if (VDM_ID_KIND(&vbh->id) != expected_kind ||
+ VDM_ID_BLKNO(&vbh->id) != vdit_size ||
+ vbh->id.node_number != VDM_NO_NODE_NUMBER)
return EINVAL;
+ if (vbi != NULL) {
+ if ((blkno >= vbi->boot_start &&
+ blkno < vbi->boot_start + vbi->boot_size) ||
+ (blkno + vbh->chunksz - 1 >= vbi->boot_start &&
+ blkno + vbh->chunksz - 1 <
+ vbi->boot_start + vbi->boot_size))
+ return EINVAL;
+ }
+
if (vbh->chunksz > largest_chunk)
largest_chunk = vbh->chunksz;
vdit_size += vbh->chunksz;
+ if (vbh->nextblk == VDM_NO_BLK_NUMBER)
+ break;
blkno = vbh->nextblk;
+ if (blkno >= DL_GETDSIZE(lp))
+ return EINVAL;
expected_kind = VDIT_PORTION_HEADER_BLOCK;
- } while (vbh->nextblk != VDM_NO_BLK_NUMBER);
+ }
/*
* Now read the first VDIT.
@@ -237,7 +269,8 @@ readvditlabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp,
vdit_end = vdit_storage;
expected_kind = VDIT_BLOCK_HEAD_BE;
blkno = VDIT_SECTOR;
- do {
+ vdit_blkno = 0;
+ for (;;) {
sbp->b_blkno = blkno;
sbp->b_bcount = largest_chunk;
CLR(sbp->b_flags, B_READ | B_WRITE | B_DONE);
@@ -253,14 +286,17 @@ readvditlabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp,
}
vdit_end = extract_vdit_portion(vdit_end, sbp->b_data,
- vbh->chunksz, expected_kind);
+ vbh->chunksz, vdit_blkno, expected_kind);
if (vdit_end == NULL) {
error = EINVAL;
goto done;
}
+ if (vbh->nextblk == VDM_NO_BLK_NUMBER)
+ break;
+ vdit_blkno += vbh->chunksz;
blkno = vbh->nextblk;
expected_kind = VDIT_PORTION_HEADER_BLOCK;
- } while (vbh->nextblk != VDM_NO_BLK_NUMBER);
+ }
/*
* Now walk the VDIT entries.
@@ -370,19 +406,23 @@ done:
* as we go.
*/
char *
-extract_vdit_portion(char *dst, const char *src, unsigned int nsec, int kind)
+extract_vdit_portion(char *dst, const char *src, unsigned int nsec,
+ unsigned int vdit_blkno, int kind)
{
struct vdit_block_header *vbh;
for (; nsec != 0; nsec--) {
vbh = (struct vdit_block_header *)src;
- if (VDM_ID_KIND(&vbh->id) != kind)
+ if (VDM_ID_KIND(&vbh->id) != kind ||
+ VDM_ID_BLKNO(&vbh->id) != vdit_blkno ||
+ vbh->id.node_number != VDM_NO_NODE_NUMBER)
return NULL;
kind = VDIT_BLOCK;
memcpy(dst, src + sizeof *vbh, dbtob(1) - sizeof *vbh);
dst += dbtob(1) - sizeof *vbh;
src += dbtob(1);
+ vdit_blkno++;
}
return dst;
diff --git a/sys/arch/aviion/include/disklabel.h b/sys/arch/aviion/include/disklabel.h
index 06a2609bd69..a2e5a94d8e4 100644
--- a/sys/arch/aviion/include/disklabel.h
+++ b/sys/arch/aviion/include/disklabel.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: disklabel.h,v 1.12 2013/09/28 19:25:25 miod Exp $ */
+/* $OpenBSD: disklabel.h,v 1.13 2013/09/29 12:17:59 miod Exp $ */
/*
* Copyright (c) 2010 Miodrag Vallat.
@@ -75,7 +75,7 @@ struct vdm_self_id {
#define VDM_ID_KIND(id) ((id)->u._kind)
#define VDM_BLKNO_MASK 0x00ffffff /* low 24 bits */
-#define VDM_ID_BLKNO(id) ((id)->u._blkno) & VDM_BLKNO_MASK)
+#define VDM_ID_BLKNO(id) (((id)->u._blkno) & VDM_BLKNO_MASK)
#define VDM_NO_NODE_NUMBER 012345670123
#define VDM_NO_BLK_NUMBER 0xffffffff