From: Karel Zak Date: Mon, 14 Jul 2014 12:53:41 +0000 (+0200) Subject: libfdisk: make first sector buffer usage more robust X-Git-Tag: v2.25~82 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7c2cfb18964b00881e65c461742af9038bd5b287;p=thirdparty%2Futil-linux.git libfdisk: make first sector buffer usage more robust $ ~/util-linux/fdisk -b 4096 xxx .. Segmentation fault The buffer has to be reinitialized always when we apply a new device properties (e.g. sector size). Reported-by: Bernhard Voelker Signed-off-by: Karel Zak --- diff --git a/libfdisk/src/alignment.c b/libfdisk/src/alignment.c index a456b98b5c..65b2c4a23f 100644 --- a/libfdisk/src/alignment.c +++ b/libfdisk/src/alignment.c @@ -239,6 +239,8 @@ int fdisk_apply_user_device_properties(struct fdisk_context *cxt) recount_geometry(cxt); fdisk_reset_alignment(cxt); + if (cxt->firstsector_bufsz != cxt->sector_size) + fdisk_read_firstsector(cxt); DBG(CXT, ul_debugobj(cxt, "new C/H/S: %u/%u/%u", (unsigned) cxt->geom.cylinders, @@ -484,9 +486,8 @@ int fdisk_reset_alignment(struct fdisk_context *cxt) if (cxt->label && cxt->label->op->reset_alignment) rc = cxt->label->op->reset_alignment(cxt); - DBG(CXT, ul_debugobj(cxt, "%s alignment reseted to: " + DBG(CXT, ul_debugobj(cxt, "alignment reseted to: " "first LBA=%ju, last LBA=%ju, grain=%lu [rc=%d]", - cxt->label ? cxt->label->name : NULL, (uintmax_t) cxt->first_lba, (uintmax_t) cxt->last_lba, cxt->grain, rc)); return rc; diff --git a/libfdisk/src/context.c b/libfdisk/src/context.c index 5fc4c6526b..2e224b363e 100644 --- a/libfdisk/src/context.c +++ b/libfdisk/src/context.c @@ -180,6 +180,7 @@ static void reset_context(struct fdisk_context *cxt) cxt->dev_fd = -1; cxt->dev_path = NULL; cxt->firstsector = NULL; + cxt->firstsector_bufsz = 0; fdisk_zeroize_device_properties(cxt); diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c index 5453eb3d76..e23abbbe8b 100644 --- a/libfdisk/src/dos.c +++ b/libfdisk/src/dos.c @@ -586,6 +586,7 @@ static int dos_get_disklabel_id(struct fdisk_context *cxt, char **id) static int dos_create_disklabel(struct fdisk_context *cxt) { unsigned int id; + int rc; assert(cxt); assert(cxt->label); @@ -597,7 +598,9 @@ static int dos_create_disklabel(struct fdisk_context *cxt) random_get_bytes(&id, sizeof(id)); dos_init(cxt); - fdisk_zeroize_firstsector(cxt); + rc = fdisk_init_firstsector_buffer(cxt); + if (rc) + return rc; fdisk_label_set_changed(cxt->label, 1); /* Generate an MBR ID for this disk */ diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h index f5b4bb8edb..ea6e291b1c 100644 --- a/libfdisk/src/fdiskP.h +++ b/libfdisk/src/fdiskP.h @@ -338,7 +338,9 @@ struct fdisk_ask { struct fdisk_context { int dev_fd; /* device descriptor */ char *dev_path; /* device path */ + unsigned char *firstsector; /* buffer with master boot record */ + unsigned long firstsector_bufsz; /* topology */ unsigned long io_size; /* I/O size used by fdisk */ @@ -418,7 +420,7 @@ extern int fdisk_apply_user_device_properties(struct fdisk_context *cxt); extern void fdisk_zeroize_device_properties(struct fdisk_context *cxt); /* utils.c */ -extern void fdisk_zeroize_firstsector(struct fdisk_context *cxt); +extern int fdisk_init_firstsector_buffer(struct fdisk_context *cxt); extern int fdisk_read_firstsector(struct fdisk_context *cxt); extern char *fdisk_partname(const char *dev, size_t partno); diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c index 1ee1b49a23..db8651f46b 100644 --- a/libfdisk/src/gpt.c +++ b/libfdisk/src/gpt.c @@ -360,11 +360,14 @@ static inline int partition_unused(const struct gpt_entry *e) static int gpt_mknew_pmbr(struct fdisk_context *cxt) { struct gpt_legacy_mbr *pmbr = NULL; + int rc; if (!cxt || !cxt->firstsector) return -ENOSYS; - fdisk_zeroize_firstsector(cxt); + rc = fdisk_init_firstsector_buffer(cxt); + if (rc) + return rc; pmbr = (struct gpt_legacy_mbr *) cxt->firstsector; diff --git a/libfdisk/src/sgi.c b/libfdisk/src/sgi.c index cd12d80492..cf1354132a 100644 --- a/libfdisk/src/sgi.c +++ b/libfdisk/src/sgi.c @@ -908,6 +908,7 @@ static int sgi_create_disklabel(struct fdisk_context *cxt) { struct fdisk_sgi_label *sgi; struct sgi_disklabel *sgilabel; + int rc; assert(cxt); assert(cxt->label); @@ -936,7 +937,10 @@ static int sgi_create_disklabel(struct fdisk_context *cxt) } } #endif - fdisk_zeroize_firstsector(cxt); + rc = fdisk_init_firstsector_buffer(cxt); + if (rc) + return rc; + sgi = (struct fdisk_sgi_label *) cxt->label; sgi->header = (struct sgi_disklabel *) cxt->firstsector; diff --git a/libfdisk/src/sun.c b/libfdisk/src/sun.c index 734f5cd7d7..50bdf8668a 100644 --- a/libfdisk/src/sun.c +++ b/libfdisk/src/sun.c @@ -195,13 +195,17 @@ static int sun_create_disklabel(struct fdisk_context *cxt) unsigned int ndiv; struct fdisk_sun_label *sun; /* libfdisk sun handler */ struct sun_disklabel *sunlabel; /* on disk data */ + int rc = 0; assert(cxt); assert(cxt->label); assert(fdisk_is_disklabel(cxt, SUN)); /* map first sector to header */ - fdisk_zeroize_firstsector(cxt); + rc = fdisk_init_firstsector_buffer(cxt); + if (rc) + return rc; + sun = (struct fdisk_sun_label *) cxt->label; sun->header = (struct sun_disklabel *) cxt->firstsector; diff --git a/libfdisk/src/utils.c b/libfdisk/src/utils.c index 65abfbc1cb..e809c6e4ff 100644 --- a/libfdisk/src/utils.c +++ b/libfdisk/src/utils.c @@ -4,35 +4,50 @@ #include - /* * Zeros in-memory first sector buffer */ -void fdisk_zeroize_firstsector(struct fdisk_context *cxt) +int fdisk_init_firstsector_buffer(struct fdisk_context *cxt) { - if (!cxt || !cxt->firstsector) - return; + if (!cxt) + return -EINVAL; + + if (!cxt->firstsector || cxt->firstsector_bufsz != cxt->sector_size) { + /* Let's allocate a new buffer if no allocated yet, or the + * current buffer has incorrect size */ + free(cxt->firstsector); + + DBG(CXT, ul_debugobj(cxt, "initialize in-memory first sector " + "buffer [sector_size=%lu]", cxt->sector_size)); + cxt->firstsector = calloc(1, cxt->sector_size); + if (!cxt->firstsector) + return -ENOMEM; + + cxt->firstsector_bufsz = cxt->sector_size; + return 0; + } DBG(CXT, ul_debugobj(cxt, "zeroize in-memory first sector buffer")); - memset(cxt->firstsector, 0, cxt->sector_size); + memset(cxt->firstsector, 0, cxt->firstsector_bufsz); + return 0; } int fdisk_read_firstsector(struct fdisk_context *cxt) { ssize_t r; + int rc; assert(cxt); assert(cxt->sector_size); - DBG(CXT, ul_debugobj(cxt, "initialize first sector " - "buffer [sector_size=%lu]", cxt->sector_size)); + rc = fdisk_init_firstsector_buffer(cxt); + if (rc) + return rc; - if (!cxt->firstsector) { - cxt->firstsector = calloc(1, cxt->sector_size); - if (!cxt->firstsector) - return -ENOMEM; - } else - fdisk_zeroize_firstsector(cxt); + assert(cxt->sector_size == cxt->firstsector_bufsz); + + DBG(CXT, ul_debugobj(cxt, "reading first sector " + "buffer [sector_size=%lu]", cxt->sector_size)); r = read(cxt->dev_fd, cxt->firstsector, cxt->sector_size);