Skip to content

Commit

Permalink
probe: Add support to determine if a device uses a GPT table or not
Browse files Browse the repository at this point in the history
In accordance with issue #53, we must only use the PartUUID for root=
entries when we *know* that the partition definitely resides on a GPT
disk.

Whilst an EFI System Partition must live on a GPT disk to be considered
a valid ESP, there is no such constraint on the rootfs itself. Cases
emerged during testing of an MBR rootfs partition, with a GPT disk used
to house the ESP itself.

This change ensures we only ever write a root=PARTUUID if we're fully
certain of the topology, otherwise all bootloaders will automatically
fall back to root=UUID entries.

Signed-off-by: Ikey Doherty <[email protected]>
  • Loading branch information
Ikey Doherty authored and bryteise committed Mar 29, 2017
1 parent d055bd4 commit b50c460
Show file tree
Hide file tree
Showing 10 changed files with 438 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ check_os_release
check_uefi
check_grub2
check_select_bootloader
check_probe

*.log
*.trs
Expand Down
21 changes: 20 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ TESTS = \
check_os_release \
check_uefi \
check_grub2 \
check_select_bootloader
check_select_bootloader \
check_probe

check_PROGRAMS = $(TESTS)

Expand Down Expand Up @@ -298,6 +299,24 @@ check_select_bootloader_LDADD = \
$(BLKID_LIBS) \
$(CHECK_LIBS)

check_probe_SOURCES = \
tests/check-probe.c \
tests/blkid-harness.h \
tests/system-harness.h \
tests/harness.h \
tests/harness.c

check_probe_CFLAGS = \
$(BLKID_CFLAGS) \
$(CHECK_CFLAGS) \
$(AM_CFLAGS)

check_probe_LDADD = \
libcbm.la \
src/libnica/libnica.la \
$(BLKID_LIBS) \
$(CHECK_LIBS)


@VALGRIND_CHECK_RULES@

Expand Down
21 changes: 21 additions & 0 deletions src/lib/blkid_stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ static CbmBlkidOps default_blkid_ops = {
.partition_get_flags = blkid_partition_get_flags,
.partition_get_uuid = blkid_partition_get_uuid,

/* Partition table functions */
.partlist_get_table = blkid_partlist_get_table,
.parttable_get_type = blkid_parttable_get_type,

/* Misc */
.devno_to_wholedisk = cbm_blkid_devno_to_wholedisk_wrapped,
};
Expand Down Expand Up @@ -85,6 +89,10 @@ void cbm_blkid_set_vtable(CbmBlkidOps *ops)
assert(blkid_ops->partition_get_flags != NULL);
assert(blkid_ops->partition_get_uuid != NULL);

/* partition table functions */
assert(blkid_ops->partlist_get_table != NULL);
assert(blkid_ops->parttable_get_type != NULL);

/* misc */
assert(blkid_ops->devno_to_wholedisk != NULL);
}
Expand Down Expand Up @@ -160,6 +168,19 @@ const char *cbm_blkid_partition_get_uuid(blkid_partition par)
return blkid_ops->partition_get_uuid(par);
}

/**
* Partition table related wrappers
*/
blkid_parttable cbm_blkid_partlist_get_table(blkid_partlist ls)
{
return blkid_ops->partlist_get_table(ls);
}

const char *cbm_blkid_parttable_get_type(blkid_parttable tab)
{
return blkid_ops->parttable_get_type(tab);
}

/**
* Misc functions
*/
Expand Down
20 changes: 20 additions & 0 deletions src/lib/blkid_stub.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ typedef struct CbmBlkidOps {
unsigned long long (*partition_get_flags)(blkid_partition par);
const char *(*partition_get_uuid)(blkid_partition par);

/* Partition table functions */
blkid_parttable (*partlist_get_table)(blkid_partlist ls);
const char *(*parttable_get_type)(blkid_parttable tab);

/* Misc functions */
int (*devno_to_wholedisk)(dev_t dev, char *diskname, size_t len, dev_t *diskdevno);
} CbmBlkidOps;
Expand Down Expand Up @@ -70,6 +74,16 @@ typedef struct CbmBlkidOps {
*/
#define CBM_BLKID_PARTITION_SET ((blkid_partition)1)

/**
* Define a "set" blkid_parttable for testing
*/
#define CBM_BLKID_PARTTABLE_SET ((blkid_parttable)1)

/**
* Define an empty blkid_parttable for testing
*/
#define CBM_BLKID_PARTTABLE_NULL ((blkid_parttable)0)

/**
* Reset the blkid vtable
*/
Expand Down Expand Up @@ -105,6 +119,12 @@ blkid_partition cbm_blkid_partlist_get_partition(blkid_partlist ls, int n);
unsigned long long cbm_blkid_partition_get_flags(blkid_partition par);
const char *cbm_blkid_partition_get_uuid(blkid_partition par);

/**
* Partition table related wrappers
*/
blkid_parttable cbm_blkid_partlist_get_table(blkid_partlist ls);
const char *cbm_blkid_parttable_get_type(blkid_parttable tab);

/**
* Misc related wrappers
*/
Expand Down
71 changes: 71 additions & 0 deletions src/lib/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <unistd.h>

#include "blkid_stub.h"
#include "files.h"
#include "log.h"
#include "probe.h"
#include "system_stub.h"
Expand Down Expand Up @@ -123,6 +124,68 @@ static char *cbm_get_luks_uuid(const char *part)
return ret;
}

/**
* Determine whether the probe lives on a GPT disk or not,
* which is the only instance in which we'll use PartUUID
*/
static bool cbm_probe_is_gpt(const char *path)
{
autofree(char) *parent_disk = NULL;
blkid_probe probe = NULL;
blkid_partlist parts = NULL;
blkid_parttable table = NULL;
bool ret = false;
const char *table_type = NULL;

/* Could be a weird image type or --path into chroot */
parent_disk = get_parent_disk((char *)path);
if (!parent_disk) {
return false;
}

probe = cbm_blkid_new_probe_from_filename(parent_disk);
if (!probe) {
LOG_ERROR("Unable to blkid probe %s", parent_disk);
return NULL;
}

cbm_blkid_probe_enable_superblocks(probe, 1);
cbm_blkid_probe_set_superblocks_flags(probe, BLKID_SUBLKS_TYPE);
cbm_blkid_probe_enable_partitions(probe, 1);
cbm_blkid_probe_set_partitions_flags(probe, BLKID_PARTS_ENTRY_DETAILS);

if (cbm_blkid_do_safeprobe(probe) != 0) {
LOG_ERROR("Error probing filesystem of %s: %s", parent_disk, strerror(errno));
goto clean;
}

parts = cbm_blkid_probe_get_partitions(probe);
if (cbm_blkid_partlist_numof_partitions(parts) <= 0) {
/* No partitions */
goto clean;
}

/* Grab the partition table */
table = cbm_blkid_partlist_get_table(parts);
if (!table) {
LOG_ERROR("Unable to discover partitiojn table for %s: %s",

This comment has been minimized.

Copy link
@benwaffle

benwaffle Mar 29, 2017

partitiojn

This comment has been minimized.

Copy link
@ikeydoherty

ikeydoherty Mar 29, 2017

Contributor

ah crap - thanks bud

This comment has been minimized.

Copy link
@jamesmshaker

jamesmshaker via email Mar 29, 2017

parent_disk,
strerror(errno));
goto clean;
}

/* Determine the partition table type. We only care if its GPT. */
table_type = cbm_blkid_parttable_get_type(table);
if (table_type && streq(table_type, "gpt")) {
ret = true;
}

clean:
cbm_blkid_free_probe(probe);
errno = 0;
return ret;
}

CbmDeviceProbe *cbm_probe_path(const char *path)
{
CbmDeviceProbe probe = { 0 };
Expand Down Expand Up @@ -177,6 +240,14 @@ CbmDeviceProbe *cbm_probe_path(const char *path)
}
}

/* If the device isn't GPT, clear out the the PartUUID */
probe.gpt = cbm_probe_is_gpt(path);
if (!probe.gpt && probe.part_uuid) {
free(probe.part_uuid);
probe.part_uuid = NULL;
}

/* Now check we have at least one UUID value */
if (!probe.part_uuid && !probe.uuid) {
LOG_ERROR("Unable to find UUID for %s: %s", devnode, strerror(errno));
}
Expand Down
6 changes: 6 additions & 0 deletions src/lib/probe.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@

#define _GNU_SOURCE

#include <stdbool.h>
#include <sys/types.h>

#include "util.h"

/**
* A CbmCbmDeviceProbe is the result of a cbm_probe_path operation, caching
* fields useful to clr-boot-manager in terms of partition analysis.
Expand All @@ -24,6 +27,7 @@ typedef struct CbmDeviceProbe {
char *part_uuid; /**< PartUUID for GPT partitions */
char *luks_uuid; /**< Parent LUKS UUID for the partition */
dev_t dev; /**< The device itself */
bool gpt; /**<Whether this device belongs to a GPT disk */
} CbmDeviceProbe;

/**
Expand All @@ -36,6 +40,8 @@ CbmDeviceProbe *cbm_probe_path(const char *path);
*/
void cbm_probe_free(CbmDeviceProbe *probe);

DEF_AUTOFREE(CbmDeviceProbe, cbm_probe_free)

/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
Expand Down
16 changes: 16 additions & 0 deletions tests/blkid-harness.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ static inline int test_blkid_devno_to_wholedisk(__cbm_unused__ dev_t dev,
return -1;
}

static inline blkid_parttable test_blkid_partlist_get_table(__cbm_unused__ blkid_partlist ls)
{
/* Return a "valid" partition table */
return CBM_BLKID_PARTTABLE_SET;
}

static inline const char *test_blkid_parttable_get_type(__cbm_unused__ blkid_parttable tab)
{
/* Return correct gpt identifier */
return "gpt";
}

/**
* Default vtable for testing. Copy into a local struct and override specific
* fields.
Expand All @@ -139,6 +151,10 @@ CbmBlkidOps BlkidTestOps = {
.partition_get_flags = test_blkid_partition_get_flags,
.partition_get_uuid = test_blkid_partition_get_uuid,

/* Partition table functions */
.partlist_get_table = test_blkid_partlist_get_table,
.parttable_get_type = test_blkid_parttable_get_type,

/* Misc */
.devno_to_wholedisk = test_blkid_devno_to_wholedisk,
};
Expand Down
Loading

0 comments on commit b50c460

Please sign in to comment.