Bug 147851

Summary: [geom] [panic] graid3 panic: g_read_data: invalid length 262144
Product: Base System Reporter: Rebecca Cran <bcran>
Component: kernAssignee: Andrey V. Elsukov <ae>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description Rebecca Cran freebsd_committer freebsd_triage 2010-06-14 14:40:01 UTC
When running:

graid3 label -v -h -s 131072 -r home /dev/ada1 /dev/ada2 /dev/ada3

the following panic occurs:

panic: g_read_data(): invalid length 262144

g_read_data()
g_part_gpt_probe()
g_part_probe()
g_part_taste()
g_new_provider_event()
g_run_events()
g_event_procbody()
fork_exit()
fork_trampoline()

How-To-Repeat: graid3 label -v -h -s 131072 -r <label> disk1 disk2 disk3
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2010-06-15 02:19:02 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-geom

Over to maintainer(s).
Comment 2 Andrey V. Elsukov freebsd_committer freebsd_triage 2011-01-11 10:27:37 UTC
Responsible Changed
From-To: freebsd-geom->ae

Take it.
Comment 3 dfilter service freebsd_committer freebsd_triage 2011-01-12 13:55:20 UTC
Author: ae
Date: Wed Jan 12 13:55:01 2011
New Revision: 217305
URL: http://svn.freebsd.org/changeset/base/217305

Log:
  Sector size can not be greater than MAXPHYS. Since GRAID3 calculates
  sector size from user-specified block size, report to user about
  big blocksize.
  
  PR:		kern/147851
  MFC after:	1 week

Modified:
  head/sbin/geom/class/raid3/geom_raid3.c
  head/sys/geom/raid3/g_raid3.c

Modified: head/sbin/geom/class/raid3/geom_raid3.c
==============================================================================
--- head/sbin/geom/class/raid3/geom_raid3.c	Wed Jan 12 13:16:35 2011	(r217304)
+++ head/sbin/geom/class/raid3/geom_raid3.c	Wed Jan 12 13:55:01 2011	(r217305)
@@ -213,6 +213,11 @@ raid3_label(struct gctl_req *req)
 	md.md_sectorsize = sectorsize * (nargs - 2);
 	md.md_mediasize -= (md.md_mediasize % md.md_sectorsize);
 
+	if (md.md_sectorsize > MAXPHYS) {
+		gctl_error(req, "The blocksize is too big.");
+		return;
+	}
+
 	/*
 	 * Clear last sector first, to spoil all components if device exists.
 	 */

Modified: head/sys/geom/raid3/g_raid3.c
==============================================================================
--- head/sys/geom/raid3/g_raid3.c	Wed Jan 12 13:16:35 2011	(r217304)
+++ head/sys/geom/raid3/g_raid3.c	Wed Jan 12 13:55:01 2011	(r217305)
@@ -2913,6 +2913,10 @@ g_raid3_read_metadata(struct g_consumer 
 		    cp->provider->name);
 		return (error);
 	}
+	if (md->md_sectorsize > MAXPHYS) {
+		G_RAID3_DEBUG(0, "The blocksize is too big.");
+		return (EINVAL);
+	}
 
 	return (0);
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 4 dfilter service freebsd_committer freebsd_triage 2011-01-18 09:53:00 UTC
Author: ae
Date: Tue Jan 18 09:52:53 2011
New Revision: 217531
URL: http://svn.freebsd.org/changeset/base/217531

Log:
  Limit maximum number of GPT entries to 4k. It is most realistic value
  and can prevent kernel memory exhausting when big value is specified
  from command line.
  
  Split reading and writing operation to several iteration to do not
  trigger KASSERT when data length is greater than MAXPHYS.
  
  PR:             kern/144962, kern/147851
  MFC after:      2 weeks

Modified:
  head/sys/geom/part/g_part_gpt.c

Modified: head/sys/geom/part/g_part_gpt.c
==============================================================================
--- head/sys/geom/part/g_part_gpt.c	Tue Jan 18 06:24:52 2011	(r217530)
+++ head/sys/geom/part/g_part_gpt.c	Tue Jan 18 09:52:53 2011	(r217531)
@@ -134,7 +134,7 @@ static struct g_part_scheme g_part_gpt_s
 	sizeof(struct g_part_gpt_table),
 	.gps_entrysz = sizeof(struct g_part_gpt_entry),
 	.gps_minent = 128,
-	.gps_maxent = INT_MAX,
+	.gps_maxent = 4096,
 	.gps_bootcodesz = MBRSIZE,
 };
 G_PART_SCHEME_DECLARE(g_part_gpt);
@@ -317,7 +317,7 @@ gpt_read_tbl(struct g_part_gpt_table *ta
 	struct g_provider *pp;
 	struct gpt_ent *ent, *tbl;
 	char *buf, *p;
-	unsigned int idx, sectors, tblsz;
+	unsigned int idx, sectors, tblsz, size;
 	int error;
 
 	if (hdr == NULL)
@@ -329,11 +329,19 @@ gpt_read_tbl(struct g_part_gpt_table *ta
 	table->state[elt] = GPT_STATE_MISSING;
 	tblsz = hdr->hdr_entries * hdr->hdr_entsz;
 	sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize;
-	buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, 
-	    sectors * pp->sectorsize, &error);
-	if (buf == NULL)
-		return (NULL);
-
+	buf = g_malloc(sectors * pp->sectorsize, M_WAITOK | M_ZERO);
+	for (idx = 0; idx < sectors; idx += MAXPHYS / pp->sectorsize) {
+		size = (sectors - idx > MAXPHYS / pp->sectorsize) ?  MAXPHYS:
+		    (sectors - idx) * pp->sectorsize;
+		p = g_read_data(cp, (table->lba[elt] + idx) * pp->sectorsize,
+		    size, &error);
+		if (p == NULL) {
+			g_free(buf);
+			return (NULL);
+		}
+		bcopy(p, buf + idx * pp->sectorsize, size);
+		g_free(p);
+	}
 	table->state[elt] = GPT_STATE_CORRUPT;
 	if (crc32(buf, tblsz) != hdr->hdr_crc_table) {
 		g_free(buf);
@@ -986,10 +994,15 @@ g_part_gpt_write(struct g_part_table *ba
 	crc = crc32(buf, table->hdr->hdr_size);
 	le32enc(buf + 16, crc);
 
-	error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize,
-	    buf + pp->sectorsize, tblsz * pp->sectorsize);
-	if (error)
-		goto out;
+	for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
+		error = g_write_data(cp,
+		    (table->lba[GPT_ELT_PRITBL] + index) * pp->sectorsize,
+		    buf + (index + 1) * pp->sectorsize,
+		    (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
+		    (tblsz - index) * pp->sectorsize);
+		if (error)
+			goto out;
+	}
 	error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize,
 	    buf, pp->sectorsize);
 	if (error)
@@ -1003,10 +1016,15 @@ g_part_gpt_write(struct g_part_table *ba
 	crc = crc32(buf, table->hdr->hdr_size);
 	le32enc(buf + 16, crc);
 
-	error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize,
-	    buf + pp->sectorsize, tblsz * pp->sectorsize);
-	if (error)
-		goto out;
+	for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
+		error = g_write_data(cp,
+		    (table->lba[GPT_ELT_SECTBL] + index) * pp->sectorsize,
+		    buf + (index + 1) * pp->sectorsize,
+		    (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
+		    (tblsz - index) * pp->sectorsize);
+		if (error)
+			goto out;
+	}
 	error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize,
 	    buf, pp->sectorsize);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 5 Andrey V. Elsukov freebsd_committer freebsd_triage 2011-01-18 10:11:20 UTC
State Changed
From-To: open->patched

Patched in head/.
Comment 6 dfilter service freebsd_committer freebsd_triage 2011-01-19 05:13:45 UTC
Author: ae
Date: Wed Jan 19 05:13:40 2011
New Revision: 217572
URL: http://svn.freebsd.org/changeset/base/217572

Log:
  MFC r217305:
    Sector size can not be greater than MAXPHYS. Since GRAID3 calculates
    sector size from user-specified block size, report to user about
    big blocksize.
  
    PR:		kern/147851

Modified:
  stable/8/sbin/geom/class/raid3/geom_raid3.c
  stable/8/sys/geom/raid3/g_raid3.c
Directory Properties:
  stable/8/sbin/geom/   (props changed)
  stable/8/sbin/geom/class/multipath/   (props changed)
  stable/8/sbin/geom/class/part/   (props changed)
  stable/8/sbin/geom/class/sched/gsched.8   (props changed)
  stable/8/sbin/geom/class/stripe/   (props changed)
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sbin/geom/class/raid3/geom_raid3.c
==============================================================================
--- stable/8/sbin/geom/class/raid3/geom_raid3.c	Wed Jan 19 05:08:32 2011	(r217571)
+++ stable/8/sbin/geom/class/raid3/geom_raid3.c	Wed Jan 19 05:13:40 2011	(r217572)
@@ -212,6 +212,11 @@ raid3_label(struct gctl_req *req)
 	md.md_sectorsize = sectorsize * (nargs - 2);
 	md.md_mediasize -= (md.md_mediasize % md.md_sectorsize);
 
+	if (md.md_sectorsize > MAXPHYS) {
+		gctl_error(req, "The blocksize is too big.");
+		return;
+	}
+
 	/*
 	 * Clear last sector first, to spoil all components if device exists.
 	 */

Modified: stable/8/sys/geom/raid3/g_raid3.c
==============================================================================
--- stable/8/sys/geom/raid3/g_raid3.c	Wed Jan 19 05:08:32 2011	(r217571)
+++ stable/8/sys/geom/raid3/g_raid3.c	Wed Jan 19 05:13:40 2011	(r217572)
@@ -2913,6 +2913,10 @@ g_raid3_read_metadata(struct g_consumer 
 		    cp->provider->name);
 		return (error);
 	}
+	if (md->md_sectorsize > MAXPHYS) {
+		G_RAID3_DEBUG(0, "The blocksize is too big.");
+		return (EINVAL);
+	}
 
 	return (0);
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 7 dfilter service freebsd_committer freebsd_triage 2011-02-01 09:27:38 UTC
Author: ae
Date: Tue Feb  1 09:27:28 2011
New Revision: 218162
URL: http://svn.freebsd.org/changeset/base/218162

Log:
  MFC r217531:
    Limit maximum number of GPT entries to 4k. It is most realistic value
    and can prevent kernel memory exhausting when big value is specified
    from command line.
  
    Split reading and writing operation to several iterations to do not
    trigger KASSERT when data length is greater than MAXPHYS.
  
    PR:             kern/144962, kern/147851

Modified:
  stable/8/sys/geom/part/g_part_gpt.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/geom/part/g_part_gpt.c
==============================================================================
--- stable/8/sys/geom/part/g_part_gpt.c	Tue Feb  1 09:27:24 2011	(r218161)
+++ stable/8/sys/geom/part/g_part_gpt.c	Tue Feb  1 09:27:28 2011	(r218162)
@@ -134,7 +134,7 @@ static struct g_part_scheme g_part_gpt_s
 	sizeof(struct g_part_gpt_table),
 	.gps_entrysz = sizeof(struct g_part_gpt_entry),
 	.gps_minent = 128,
-	.gps_maxent = INT_MAX,
+	.gps_maxent = 4096,
 	.gps_bootcodesz = MBRSIZE,
 };
 G_PART_SCHEME_DECLARE(g_part_gpt);
@@ -317,7 +317,7 @@ gpt_read_tbl(struct g_part_gpt_table *ta
 	struct g_provider *pp;
 	struct gpt_ent *ent, *tbl;
 	char *buf, *p;
-	unsigned int idx, sectors, tblsz;
+	unsigned int idx, sectors, tblsz, size;
 	int error;
 
 	if (hdr == NULL)
@@ -329,11 +329,19 @@ gpt_read_tbl(struct g_part_gpt_table *ta
 	table->state[elt] = GPT_STATE_MISSING;
 	tblsz = hdr->hdr_entries * hdr->hdr_entsz;
 	sectors = (tblsz + pp->sectorsize - 1) / pp->sectorsize;
-	buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, 
-	    sectors * pp->sectorsize, &error);
-	if (buf == NULL)
-		return (NULL);
-
+	buf = g_malloc(sectors * pp->sectorsize, M_WAITOK | M_ZERO);
+	for (idx = 0; idx < sectors; idx += MAXPHYS / pp->sectorsize) {
+		size = (sectors - idx > MAXPHYS / pp->sectorsize) ?  MAXPHYS:
+		    (sectors - idx) * pp->sectorsize;
+		p = g_read_data(cp, (table->lba[elt] + idx) * pp->sectorsize,
+		    size, &error);
+		if (p == NULL) {
+			g_free(buf);
+			return (NULL);
+		}
+		bcopy(p, buf + idx * pp->sectorsize, size);
+		g_free(p);
+	}
 	table->state[elt] = GPT_STATE_CORRUPT;
 	if (crc32(buf, tblsz) != hdr->hdr_crc_table) {
 		g_free(buf);
@@ -986,10 +994,15 @@ g_part_gpt_write(struct g_part_table *ba
 	crc = crc32(buf, table->hdr->hdr_size);
 	le32enc(buf + 16, crc);
 
-	error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize,
-	    buf + pp->sectorsize, tblsz * pp->sectorsize);
-	if (error)
-		goto out;
+	for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
+		error = g_write_data(cp,
+		    (table->lba[GPT_ELT_PRITBL] + index) * pp->sectorsize,
+		    buf + (index + 1) * pp->sectorsize,
+		    (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
+		    (tblsz - index) * pp->sectorsize);
+		if (error)
+			goto out;
+	}
 	error = g_write_data(cp, table->lba[GPT_ELT_PRIHDR] * pp->sectorsize,
 	    buf, pp->sectorsize);
 	if (error)
@@ -1003,10 +1016,15 @@ g_part_gpt_write(struct g_part_table *ba
 	crc = crc32(buf, table->hdr->hdr_size);
 	le32enc(buf + 16, crc);
 
-	error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize,
-	    buf + pp->sectorsize, tblsz * pp->sectorsize);
-	if (error)
-		goto out;
+	for (index = 0; index < tblsz; index += MAXPHYS / pp->sectorsize) {
+		error = g_write_data(cp,
+		    (table->lba[GPT_ELT_SECTBL] + index) * pp->sectorsize,
+		    buf + (index + 1) * pp->sectorsize,
+		    (tblsz - index > MAXPHYS / pp->sectorsize) ? MAXPHYS:
+		    (tblsz - index) * pp->sectorsize);
+		if (error)
+			goto out;
+	}
 	error = g_write_data(cp, table->lba[GPT_ELT_SECHDR] * pp->sectorsize,
 	    buf, pp->sectorsize);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 8 Andrey V. Elsukov freebsd_committer freebsd_triage 2011-02-05 14:33:43 UTC
State Changed
From-To: patched->closed

Fix commited to head/ and stable/8.