]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: support bootbits protection from (p)MBR
authorKarel Zak <kzak@redhat.com>
Mon, 13 Apr 2015 11:40:25 +0000 (13:40 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 13 Apr 2015 11:40:25 +0000 (13:40 +0200)
Signed-off-by: Karel Zak <kzak@redhat.com>
include/pt-mbr.h
libfdisk/docs/libfdisk-sections.txt
libfdisk/src/context.c
libfdisk/src/dos.c
libfdisk/src/fdiskP.h
libfdisk/src/gpt.c
libfdisk/src/libfdisk.h.in
libfdisk/src/libfdisk.sym
libfdisk/src/sgi.c
libfdisk/src/sun.c
libfdisk/src/utils.c

index fab65ea07eb36eb060356cc27d41a7e0e2c7d874..8c4f8e6a8b9b3ba211adbcfeb1b0b65d786cae2b 100644 (file)
@@ -11,6 +11,7 @@ struct dos_partition {
 } __attribute__((packed));
 
 #define MBR_PT_OFFSET          0x1be
+#define MBR_PT_BOOTBITS_SIZE   440
 
 static inline struct dos_partition *mbr_get_partition(unsigned char *mbr, int i)
 {
index 8713d23b3e005ad277a6540423b55cb0aef51829..339c15cd38973f769730a94bb27515b0dcf74485 100644 (file)
@@ -282,6 +282,7 @@ fdisk_unref_table
 fdisk_context
 fdisk_assign_device
 fdisk_deassign_device
+fdisk_enable_bootbits_protection
 fdisk_enable_details
 fdisk_enable_listonly
 fdisk_get_alignment_offset
@@ -300,22 +301,23 @@ fdisk_get_parent
 fdisk_get_physector_size
 fdisk_get_sector_size
 fdisk_get_size_unit
-FDISK_PLURAL
-FDISK_SINGULAR
 fdisk_get_unit
 fdisk_get_units_per_sector
 fdisk_has_label
+fdisk_has_protected_bootbits
 fdisk_is_details
 fdisk_is_labeltype
 fdisk_is_listonly
 fdisk_is_readonly
 fdisk_new_context
 fdisk_new_nested_context
+FDISK_PLURAL
 fdisk_ref_context
 fdisk_set_first_lba
 fdisk_set_last_lba
 fdisk_set_size_unit
 fdisk_set_unit
+FDISK_SINGULAR
 fdisk_unref_context
 fdisk_use_cylinders
 </SECTION>
index 84867b0abe1e8413fc96df2e7364e9c4e1e48bce..efc961cf710b9d5acd59988de4a745ec0b23fc5c 100644 (file)
@@ -94,12 +94,13 @@ static int init_nested_from_parent(struct fdisk_context *cxt, int isnew)
        cxt->user_log_sector =  parent->user_log_sector;
        cxt->user_pyh_sector =  parent->user_pyh_sector;
 
-       /* parent <--> nested independent setting, initialize for new nested 
+       /* parent <--> nested independent setting, initialize for new nested
         * contexts only */
        if (isnew) {
                cxt->listonly = parent->listonly;
                cxt->display_details =  parent->display_details;
                cxt->display_in_cyl_units = parent->display_in_cyl_units;
+               cxt->protect_bootbits = parent->protect_bootbits;
        }
 
        free(cxt->dev_path);
@@ -303,6 +304,36 @@ int fdisk_has_label(struct fdisk_context *cxt)
        return cxt && cxt->label;
 }
 
+/**
+ * fdisk_has_protected_bootbits:
+ * @cxt: fdisk context
+ *
+ * Returns: return 1 if boot bits protection enabled.
+ */
+int fdisk_has_protected_bootbits(struct fdisk_context *cxt)
+{
+       return cxt && cxt->protect_bootbits;
+}
+
+/**
+ * fdisk_enable_bootbits_protection:
+ * @cxt: fdisk context
+ * @enable: 1 or 0
+ *
+ * The library zeroizes all the first sector when create a new disk label by
+ * default.  This function allows to control this behavior. For now it's
+ * supported for MBR and GPT.
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_enable_bootbits_protection(struct fdisk_context *cxt, int enable)
+{
+       if (!cxt)
+               return -EINVAL;
+       cxt->protect_bootbits = enable ? 1 : 0;
+       return 0;
+}
+
 /**
  * fdisk_get_npartitions:
  * @cxt: context
index 6468071ffbadf54f84142d6973a05a1cc00c6ea1..f2308e3e04924d18475ecf908a6329c986d0faec 100644 (file)
@@ -659,7 +659,10 @@ static int dos_create_disklabel(struct fdisk_context *cxt)
        if (!has_id)
                random_get_bytes(&id, sizeof(id));
 
-       rc = fdisk_init_firstsector_buffer(cxt);
+       if (fdisk_has_protected_bootbits(cxt))
+               rc = fdisk_init_firstsector_buffer(cxt, 0, MBR_PT_BOOTBITS_SIZE);
+       else
+               rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
        if (rc)
                return rc;
        dos_init(cxt);
index dc561f389c3388d5835f16a5bdd1016ffdd068a3..0ca498d54f992263e50e08a05e3a3651e05c620c 100644 (file)
@@ -350,6 +350,7 @@ struct fdisk_context {
        unsigned int readonly : 1,              /* don't write to the device */
                     display_in_cyl_units : 1,  /* for obscure labels */
                     display_details : 1,       /* expert display mode */
+                    protect_bootbits : 1,      /* don't zeroize fll irst sector */
                     listonly : 1;              /* list partition, nothing else */
 
        int sizeunit;                           /* SIZE fields, FDISK_SIZEUNIT_* */
@@ -402,7 +403,8 @@ extern int fdisk_apply_user_device_properties(struct fdisk_context *cxt);
 extern void fdisk_zeroize_device_properties(struct fdisk_context *cxt);
 
 /* utils.c */
-extern int fdisk_init_firstsector_buffer(struct fdisk_context *cxt);
+extern int fdisk_init_firstsector_buffer(struct fdisk_context *cxt,
+                       unsigned int protect_off, unsigned int protect_size);
 extern int fdisk_read_firstsector(struct fdisk_context *cxt);
 extern char *fdisk_partname(const char *dev, size_t partno);
 
index 9ceb01a6e921f40920be4c6fda683711188384ad..62271c11560e47087c71d664c2ef979e3676cea2 100644 (file)
@@ -27,6 +27,7 @@
 #include "bitops.h"
 #include "strutils.h"
 #include "all-io.h"
+#include "pt-mbr.h"
 
 /**
  * SECTION: gpt
@@ -406,7 +407,10 @@ static int gpt_mknew_pmbr(struct fdisk_context *cxt)
        if (!cxt || !cxt->firstsector)
                return -ENOSYS;
 
-       rc = fdisk_init_firstsector_buffer(cxt);
+       if (fdisk_has_protected_bootbits(cxt))
+               rc = fdisk_init_firstsector_buffer(cxt, 0, MBR_PT_BOOTBITS_SIZE);
+       else
+               rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
        if (rc)
                return rc;
 
index a38ef47c99234e05f02aa6c2e57f0b5797e6da59..5a14c26f159f58978622938a4370a7b05b1a6c88 100644 (file)
@@ -211,6 +211,8 @@ enum {
 int fdisk_set_size_unit(struct fdisk_context *cxt, int unit);
 int fdisk_get_size_unit(struct fdisk_context *cxt);
 
+int fdisk_has_protected_bootbits(struct fdisk_context *cxt);
+int fdisk_enable_bootbits_protection(struct fdisk_context *cxt, int enable);
 
 /* parttype.c */
 struct fdisk_parttype *fdisk_new_parttype(void);
index 5ff270b598c3d2ef430f6c8b1bc62dd06f2c652e..4d8276eca7145bcf0ed16830bb9a9a3b45d6d729 100644 (file)
@@ -244,4 +244,6 @@ FDISK_2.27 {
        fdisk_script_set_fgets;
        fdisk_script_set_userdata;
        fdisk_script_get_userdata;
+       fdisk_enable_bootbits_protection;
+       fdisk_has_protected_bootbits;
 } FDISK_2.26;
index cd4cedff07c1eb4b28427b7033373c0467fb1271..7cc68b501583c02f5cbca1c755a3e5641d5f8828 100644 (file)
@@ -965,7 +965,7 @@ static int sgi_create_disklabel(struct fdisk_context *cxt)
                }
        }
 #endif
-       rc = fdisk_init_firstsector_buffer(cxt);
+       rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
        if (rc)
                return rc;
 
index d99c39f6f5732c150de83b80c98e42c727717fc3..27e3bdd0028d82b453a1d2009979bdd95216f8c3 100644 (file)
@@ -209,7 +209,7 @@ static int sun_create_disklabel(struct fdisk_context *cxt)
        assert(fdisk_is_label(cxt, SUN));
 
        /* map first sector to header */
-       rc = fdisk_init_firstsector_buffer(cxt);
+       rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
        if (rc)
                return rc;
 
index 482a3062dbb3babf2d20a9d8f32e2a71aa819acd..cc470d99bb78f8e8908af28a5daebf931014a9e4 100644 (file)
  * @short_description: misc fdisk functions
  */
 
+static int read_from_device(struct fdisk_context *cxt,
+               unsigned char *buf,
+               uintmax_t start, size_t size)
+{
+       ssize_t r;
+
+       assert(cxt);
+
+       DBG(CXT, ul_debugobj(cxt, "reading: offset=%ju, size=%zu",
+                               start, size));
+
+       r = lseek(cxt->dev_fd, start, SEEK_SET);
+       if (r == -1)
+       {
+               DBG(CXT, ul_debugobj(cxt, "failed to seek to offset %ju: %m", start));
+               return -errno;
+       }
+
+       r = read(cxt->dev_fd, buf, size);
+       if (r < 0 || r != size) {
+               if (!errno)
+                       errno = EINVAL; /* probably too small file/device */
+               DBG(CXT, ul_debugobj(cxt, "failed to read %zu from offset %ju: %m",
+                               size, start));
+               return -errno;
+       }
+
+       return 0;
+}
+
+
 /*
  * Zeros in-memory first sector buffer
  */
-int fdisk_init_firstsector_buffer(struct fdisk_context *cxt)
+int fdisk_init_firstsector_buffer(struct fdisk_context *cxt,
+                                 unsigned int protect_off,
+                                 unsigned int protect_size)
 {
        if (!cxt)
                return -EINVAL;
 
+       assert(protect_off + protect_size <= cxt->sector_size);
+
        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 */
@@ -36,43 +71,37 @@ int fdisk_init_firstsector_buffer(struct fdisk_context *cxt)
 
        DBG(CXT, ul_debugobj(cxt, "zeroize in-memory first sector buffer"));
        memset(cxt->firstsector, 0, cxt->firstsector_bufsz);
+
+       if (protect_size) {
+               /*
+                * It would be possible to reuse data from cxt->firstsector
+                * (call memset() for non-protected area only) and avoid one
+                * read() from the device, but it seems like a too fragile
+                * solution as we have no clue about stuff in the buffer --
+                * maybe it was already modified. Let's re-read from the device
+                * to be sure.                  -- kzak 13-Apr-2015
+                */
+               DBG(CXT, ul_debugobj(cxt, "first sector protection enabled -- re-reading"));
+               read_from_device(cxt, cxt->firstsector, protect_off, protect_size);
+       }
        return 0;
 }
 
 int fdisk_read_firstsector(struct fdisk_context *cxt)
 {
-       ssize_t r;
        int rc;
 
        assert(cxt);
        assert(cxt->sector_size);
 
-       rc = fdisk_init_firstsector_buffer(cxt);
+       rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
        if (rc)
                return rc;
 
        assert(cxt->sector_size == cxt->firstsector_bufsz);
 
-       DBG(CXT, ul_debugobj(cxt, "reading first sector "
-                               "buffer [sector_size=%lu]", cxt->sector_size));
-
-       r = lseek(cxt->dev_fd, 0, SEEK_SET);
-       if (r == -1)
-       {
-               DBG(CXT, ul_debugobj(cxt, "failed to seek to first sector %m"));
-               return -errno;
-       }
-
-       r = read(cxt->dev_fd, cxt->firstsector, cxt->sector_size);
 
-       if (r != cxt->sector_size) {
-               if (!errno)
-                       errno = EINVAL; /* probably too small file/device */
-               DBG(CXT, ul_debugobj(cxt, "failed to read first sector %m"));
-               return -errno;
-       }
-
-       return 0;
+       return  read_from_device(cxt, cxt->firstsector, 0, cxt->sector_size);
 }
 
 /**