From owner-svn-src-projects@FreeBSD.ORG Sat Feb 5 20:23:12 2011 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8D1D31065675; Sat, 5 Feb 2011 20:23:12 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 7D1C48FC17; Sat, 5 Feb 2011 20:23:12 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p15KNCPT039240; Sat, 5 Feb 2011 20:23:12 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p15KNCLv039238; Sat, 5 Feb 2011 20:23:12 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201102052023.p15KNCLv039238@svn.freebsd.org> From: Alexander Motin Date: Sat, 5 Feb 2011 20:23:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r218336 - projects/graid/head/sys/geom/raid X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 05 Feb 2011 20:23:12 -0000 Author: mav Date: Sat Feb 5 20:23:12 2011 New Revision: 218336 URL: http://svn.freebsd.org/changeset/base/218336 Log: Validate main metadata fields on read to avoid later surprises. Skip disks with metadata describing volumes in unsupported migration states to not damage data with wrong handling. Modified: projects/graid/head/sys/geom/raid/md_intel.c Modified: projects/graid/head/sys/geom/raid/md_intel.c ============================================================================== --- projects/graid/head/sys/geom/raid/md_intel.c Sat Feb 5 19:13:38 2011 (r218335) +++ projects/graid/head/sys/geom/raid/md_intel.c Sat Feb 5 20:23:12 2011 (r218336) @@ -330,8 +330,10 @@ intel_meta_read(struct g_consumer *cp) { struct g_provider *pp; struct intel_raid_conf *meta; + struct intel_raid_vol *mvol; + struct intel_raid_map *mmap; char *buf; - int error, i, left; + int error, i, j, k, left, size; uint32_t checksum, *ptr; pp = cp->provider; @@ -352,14 +354,15 @@ intel_meta_read(struct g_consumer *cp) g_free(buf); return (NULL); } - if (meta->config_size > 65536) { - G_RAID_DEBUG(1, "Intel metadata size looks too big: %d", + if (meta->config_size > 65536 || + meta->config_size < sizeof(struct intel_raid_conf)) { + G_RAID_DEBUG(1, "Intel metadata size looks wrong: %d", meta->config_size); g_free(buf); return (NULL); } meta = malloc(meta->config_size, M_MD_INTEL, M_WAITOK); - memcpy(meta, buf, pp->sectorsize); + memcpy(meta, buf, min(meta->config_size, pp->sectorsize)); g_free(buf); /* Read all the rest, if needed. */ @@ -392,6 +395,68 @@ intel_meta_read(struct g_consumer *cp) return (NULL); } + /* Validate metadata size. */ + size = sizeof(struct intel_raid_conf) + + sizeof(struct intel_raid_disk) * (meta->total_disks - 1) + + sizeof(struct intel_raid_vol) * meta->total_volumes; + if (size > meta->config_size) { +badsize: + G_RAID_DEBUG(1, "Intel metadata size incorrect %d < %d", + meta->config_size, size); + free(meta, M_MD_INTEL); + return (NULL); + } + for (i = 0; i < meta->total_volumes; i++) { + mvol = intel_get_volume(meta, i); + mmap = intel_get_map(mvol, 0); + size += 4 * (mmap->total_disks - 1); + if (size > meta->config_size) + goto badsize; + if (mvol->migr_state) { + size += sizeof(struct intel_raid_map); + if (size > meta->config_size) + goto badsize; + mmap = intel_get_map(mvol, 1); + size += 4 * (mmap->total_disks - 1); + if (size > meta->config_size) + goto badsize; + } + } + + /* Validate disk indexes. */ + for (i = 0; i < meta->total_volumes; i++) { + mvol = intel_get_volume(meta, i); + for (j = 0; j < (mvol->migr_state ? 2 : 1); j++) { + mmap = intel_get_map(mvol, j); + for (k = 0; k < mmap->total_disks; k++) { + if ((mmap->disk_idx[k] & INTEL_DI_IDX) > + meta->total_disks) { + G_RAID_DEBUG(1, "Intel metadata disk" + " index %d too big (>%d)", + mmap->disk_idx[k] & INTEL_DI_IDX, + meta->total_disks); + free(meta, M_MD_INTEL); + return (NULL); + } + } + } + } + + /* Validate migration types. */ + for (i = 0; i < meta->total_volumes; i++) { + mvol = intel_get_volume(meta, i); + if (mvol->migr_state && + mvol->migr_type != INTEL_MT_INIT && + mvol->migr_type != INTEL_MT_REBUILD && + mvol->migr_type != INTEL_MT_VERIFY && + mvol->migr_type != INTEL_MT_REPAIR) { + G_RAID_DEBUG(1, "Intel metadata has unsupported" + " migration type %d", mvol->migr_type); + free(meta, M_MD_INTEL); + return (NULL); + } + } + return (meta); }