Page MenuHomeFreeBSD

D8595.diff
No OneTemporary

D8595.diff

Index: head/sys/boot/i386/libi386/biosdisk.c
===================================================================
--- head/sys/boot/i386/libi386/biosdisk.c
+++ head/sys/boot/i386/libi386/biosdisk.c
@@ -39,6 +39,7 @@
*/
#include <sys/disk.h>
+#include <sys/limits.h>
#include <stand.h>
#include <machine/bootinfo.h>
#include <stdarg.h>
@@ -302,15 +303,28 @@
if (!V86_CY(v86.efl)) {
uint64_t total;
- if (params.sectors != 0)
- bd->bd_sectors = params.sectors;
+ /*
+ * Sector size must be a multiple of 512 bytes.
+ * An alternate test would be to check power of 2,
+ * powerof2(params.sector_size).
+ */
+ if (params.sector_size % BIOSDISK_SECSIZE)
+ bd->bd_sectorsize = BIOSDISK_SECSIZE;
+ else
+ bd->bd_sectorsize = params.sector_size;
+
+ total = bd->bd_sectorsize * params.sectors;
+ if (params.sectors != 0) {
+ /* Only update if we did not overflow. */
+ if (total > params.sectors)
+ bd->bd_sectors = params.sectors;
+ }
total = (uint64_t)params.cylinders *
params.heads * params.sectors_per_track;
if (bd->bd_sectors < total)
bd->bd_sectors = total;
- bd->bd_sectorsize = params.sector_size;
ret = 1;
}
DEBUG("unit 0x%x flags %x, sectors %llu, sectorsize %u",
@@ -377,8 +391,10 @@
bd_open(struct open_file *f, ...)
{
struct disk_devdesc *dev, rdev;
+ struct disk_devdesc disk;
int err, g_err;
va_list ap;
+ uint64_t size;
va_start(ap, f);
dev = va_arg(ap, struct disk_devdesc *);
@@ -389,6 +405,33 @@
BD(dev).bd_open++;
if (BD(dev).bd_bcache == NULL)
BD(dev).bd_bcache = bcache_allocate();
+
+ /*
+ * Read disk size from partition.
+ * This is needed to work around buggy BIOS systems returning
+ * wrong (truncated) disk media size.
+ * During bd_probe() we tested if the mulitplication of bd_sectors
+ * would overflow so it should be safe to perform here.
+ */
+ disk.d_dev = dev->d_dev;
+ disk.d_type = dev->d_type;
+ disk.d_unit = dev->d_unit;
+ disk.d_opendata = NULL;
+ disk.d_slice = -1;
+ disk.d_partition = -1;
+ disk.d_offset = 0;
+ if (disk_open(&disk, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
+ BD(dev).bd_sectorsize, (BD(dev).bd_flags & BD_FLOPPY) ?
+ DISK_F_NOCACHE: 0) == 0) {
+
+ if (disk_ioctl(&disk, DIOCGMEDIASIZE, &size) == 0) {
+ size /= BD(dev).bd_sectorsize;
+ if (size > BD(dev).bd_sectors)
+ BD(dev).bd_sectors = size;
+ }
+ disk_close(&disk);
+ }
+
err = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
BD(dev).bd_sectorsize, (BD(dev).bd_flags & BD_FLOPPY) ?
DISK_F_NOCACHE: 0);
@@ -486,8 +529,14 @@
bd_ioctl(struct open_file *f, u_long cmd, void *data)
{
struct disk_devdesc *dev;
+ int rc;
dev = (struct disk_devdesc *)f->f_devdata;
+
+ rc = disk_ioctl(dev, cmd, data);
+ if (rc != ENOTTY)
+ return (rc);
+
switch (cmd) {
case DIOCGSECTORSIZE:
*(u_int *)data = BD(dev).bd_sectorsize;
@@ -521,7 +570,8 @@
char *buf, size_t *rsize)
{
struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
- int blks, remaining;
+ uint64_t disk_blocks;
+ int blks;
#ifdef BD_SUPPORT_FRAGS /* XXX: sector size */
char fragbuf[BIOSDISK_SECSIZE];
size_t fragsize;
@@ -533,19 +583,43 @@
#endif
DEBUG("open_disk %p", dev);
+
+ /*
+ * Check the value of the size argument. We do have quite small
+ * heap (64MB), but we do not know good upper limit, so we check against
+ * INT_MAX here. This will also protect us against possible overflows
+ * while translating block count to bytes.
+ */
+ if (size > INT_MAX) {
+ DEBUG("too large read: %zu bytes", size);
+ return (EIO);
+ }
+
blks = size / BD(dev).bd_sectorsize;
+ if (dblk > dblk + blks)
+ return (EIO);
+
if (rsize)
*rsize = 0;
+ /* Get disk blocks, this value is either for whole disk or for partition */
+ if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks)) {
+ /* DIOCGMEDIASIZE does return bytes. */
+ disk_blocks /= BD(dev).bd_sectorsize;
+ } else {
+ /* We should not get here. Just try to survive. */
+ disk_blocks = BD(dev).bd_sectors - dev->d_offset;
+ }
+
+ /* Validate source block address. */
+ if (dblk < dev->d_offset || dblk >= dev->d_offset + disk_blocks)
+ return (EIO);
+
/*
- * Perform partial read to prevent read-ahead crossing
- * the end of disk - or any 32 bit aliases of the end.
- * Signed arithmetic is used to handle wrap-around cases
- * like we do for TCP sequence numbers.
+ * Truncate if we are crossing disk or partition end.
*/
- remaining = (int)(BD(dev).bd_sectors - dblk); /* truncate */
- if (remaining > 0 && remaining < blks) {
- blks = remaining;
+ if (dblk + blks >= dev->d_offset + disk_blocks) {
+ blks = dev->d_offset + disk_blocks - dblk;
size = blks * BD(dev).bd_sectorsize;
DEBUG("short read %d", blks);
}

File Metadata

Mime Type
text/plain
Expires
Wed, Feb 5, 10:44 PM (21 h, 19 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16482215
Default Alt Text
D8595.diff (4 KB)

Event Timeline