]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: make first sector buffer usage more robust
authorKarel Zak <kzak@redhat.com>
Mon, 14 Jul 2014 12:53:41 +0000 (14:53 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 14 Jul 2014 13:05:22 +0000 (15:05 +0200)
$ ~/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 <mail@bernhard-voelker.de>
Signed-off-by: Karel Zak <kzak@redhat.com>
libfdisk/src/alignment.c
libfdisk/src/context.c
libfdisk/src/dos.c
libfdisk/src/fdiskP.h
libfdisk/src/gpt.c
libfdisk/src/sgi.c
libfdisk/src/sun.c
libfdisk/src/utils.c

index a456b98b5c001b0bcb956ea4858c6ebfe9510e0c..65b2c4a23f5057fe945c2315d1b85ed73623a404 100644 (file)
@@ -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;
index 5fc4c6526ba5d518002d76cc275ffb1f9861c105..2e224b363e998c041da8d038b57c6916ff456a51 100644 (file)
@@ -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);
 
index 5453eb3d763ba0f2225ac03423919cd58ce00957..e23abbbe8bf3c62746eb4db46729fe88fa508058 100644 (file)
@@ -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 */
index f5b4bb8edb40414f95a98e1b613e6de1d5605bb4..ea6e291b1c81e50bd23e98b932581c14f67287a7 100644 (file)
@@ -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);
 
index 1ee1b49a2338374d18e8e06d236c8b5cc8b1e72e..db8651f46b7714ab7dbb93d14ced9816a3e36708 100644 (file)
@@ -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;
 
index cd12d8049216350ebae814f55276cc01c590186e..cf1354132a2f15707677be7d45a81f512041cf5b 100644 (file)
@@ -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;
 
index 734f5cd7d7679485ca3fa9c5b6525cd29f215f31..50bdf8668a211afd597aa75868dcdd5f8ce416f9 100644 (file)
@@ -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;
 
index 65abfbc1cb26d8d37cfa78e175bd615b7171a411..e809c6e4ffc1de785671153bb34507c82e59b7d0 100644 (file)
@@ -4,35 +4,50 @@
 
 #include <ctype.h>
 
-
 /*
  * 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);