diff options
-rw-r--r-- | include/pt-mbr.h | 1 | ||||
-rw-r--r-- | libfdisk/docs/libfdisk-sections.txt | 6 | ||||
-rw-r--r-- | libfdisk/src/context.c | 33 | ||||
-rw-r--r-- | libfdisk/src/dos.c | 5 | ||||
-rw-r--r-- | libfdisk/src/fdiskP.h | 4 | ||||
-rw-r--r-- | libfdisk/src/gpt.c | 6 | ||||
-rw-r--r-- | libfdisk/src/libfdisk.h.in | 2 | ||||
-rw-r--r-- | libfdisk/src/libfdisk.sym | 2 | ||||
-rw-r--r-- | libfdisk/src/sgi.c | 2 | ||||
-rw-r--r-- | libfdisk/src/sun.c | 2 | ||||
-rw-r--r-- | libfdisk/src/utils.c | 73 |
11 files changed, 106 insertions, 30 deletions
diff --git a/include/pt-mbr.h b/include/pt-mbr.h index fab65ea07..8c4f8e6a8 100644 --- a/include/pt-mbr.h +++ b/include/pt-mbr.h @@ -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) { diff --git a/libfdisk/docs/libfdisk-sections.txt b/libfdisk/docs/libfdisk-sections.txt index 8713d23b3..339c15cd3 100644 --- a/libfdisk/docs/libfdisk-sections.txt +++ b/libfdisk/docs/libfdisk-sections.txt @@ -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> diff --git a/libfdisk/src/context.c b/libfdisk/src/context.c index 84867b0ab..efc961cf7 100644 --- a/libfdisk/src/context.c +++ b/libfdisk/src/context.c @@ -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); @@ -304,6 +305,36 @@ int fdisk_has_label(struct fdisk_context *cxt) } /** + * 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 * diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c index 6468071ff..f2308e3e0 100644 --- a/libfdisk/src/dos.c +++ b/libfdisk/src/dos.c @@ -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); diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h index dc561f389..0ca498d54 100644 --- a/libfdisk/src/fdiskP.h +++ b/libfdisk/src/fdiskP.h @@ -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); diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c index 9ceb01a6e..62271c115 100644 --- a/libfdisk/src/gpt.c +++ b/libfdisk/src/gpt.c @@ -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; diff --git a/libfdisk/src/libfdisk.h.in b/libfdisk/src/libfdisk.h.in index a38ef47c9..5a14c26f1 100644 --- a/libfdisk/src/libfdisk.h.in +++ b/libfdisk/src/libfdisk.h.in @@ -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); diff --git a/libfdisk/src/libfdisk.sym b/libfdisk/src/libfdisk.sym index 5ff270b59..4d8276eca 100644 --- a/libfdisk/src/libfdisk.sym +++ b/libfdisk/src/libfdisk.sym @@ -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; diff --git a/libfdisk/src/sgi.c b/libfdisk/src/sgi.c index cd4cedff0..7cc68b501 100644 --- a/libfdisk/src/sgi.c +++ b/libfdisk/src/sgi.c @@ -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; diff --git a/libfdisk/src/sun.c b/libfdisk/src/sun.c index d99c39f6f..27e3bdd00 100644 --- a/libfdisk/src/sun.c +++ b/libfdisk/src/sun.c @@ -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; diff --git a/libfdisk/src/utils.c b/libfdisk/src/utils.c index 482a3062d..cc470d99b 100644 --- a/libfdisk/src/utils.c +++ b/libfdisk/src/utils.c @@ -10,14 +10,49 @@ * @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); } /** |