bootspec: if unprivileged validate partition data with udev rather than blkid directly

udev metadata access works unprivileged, which the blkid stuff doesn't
(as that needs raw device node access). Hence let's use udev if we lack
privs, and raw device access only if root.
This commit is contained in:
Lennart Poettering 2019-02-05 18:45:41 +01:00
parent ad95aa44d6
commit cedb9eec76

View file

@ -3,6 +3,7 @@
#include <stdio.h>
#include <linux/magic.h>
#include "sd-device.h"
#include "sd-id128.h"
#include "alloc-util.h"
@ -533,6 +534,94 @@ static int verify_esp_blkid(
return 0;
}
static int verify_esp_udev(
dev_t devid,
bool searching,
uint32_t *ret_part,
uint64_t *ret_pstart,
uint64_t *ret_psize,
sd_id128_t *ret_uuid) {
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
_cleanup_free_ char *node = NULL;
sd_id128_t uuid = SD_ID128_NULL;
uint64_t pstart = 0, psize = 0;
uint32_t part = 0;
const char *v;
int r;
r = device_path_make_major_minor(S_IFBLK, devid, &node);
if (r < 0)
return log_error_errno(r, "Failed to format major/minor device path: %m");
r = sd_device_new_from_devnum(&d, 'b', devid);
if (r < 0)
return log_error_errno(r, "Failed to get device from device number: %m");
r = sd_device_get_property_value(d, "ID_FS_TYPE", &v);
if (r < 0)
return log_error_errno(r, "Failed to get device property: %m");
if (!streq(v, "vfat"))
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" is not FAT.", node );
r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
if (r < 0)
return log_error_errno(r, "Failed to get device property: %m");
if (!streq(v, "gpt"))
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" is not on a GPT partition table.", node);
r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
if (r < 0)
return log_error_errno(r, "Failed to get device property: %m");
if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"))
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
if (r < 0)
return log_error_errno(r, "Failed to get device property: %m");
r = sd_id128_from_string(v, &uuid);
if (r < 0)
return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
r = sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &v);
if (r < 0)
return log_error_errno(r, "Failed to get device property: %m");
r = safe_atou32(v, &part);
if (r < 0)
return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
r = sd_device_get_property_value(d, "ID_PART_ENTRY_OFFSET", &v);
if (r < 0)
return log_error_errno(r, "Failed to get device property: %m");
r = safe_atou64(v, &pstart);
if (r < 0)
return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
r = sd_device_get_property_value(d, "ID_PART_ENTRY_SIZE", &v);
if (r < 0)
return log_error_errno(r, "Failed to get device property: %m");
r = safe_atou64(v, &psize);
if (r < 0)
return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
if (ret_part)
*ret_part = part;
if (ret_pstart)
*ret_pstart = pstart;
if (ret_psize)
*ret_psize = psize;
if (ret_uuid)
*ret_uuid = uuid;
return 0;
}
static int verify_esp(
const char *p,
bool searching,
@ -597,12 +686,19 @@ static int verify_esp(
"Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p);
/* In a container we don't have access to block devices, skip this part of the verification, we trust
* the container manager set everything up correctly on its own. Also skip the following verification
* for non-root user. */
if (detect_container() > 0 || unprivileged_mode || relax_checks)
* the container manager set everything up correctly on its own. */
if (detect_container() > 0 || relax_checks)
goto finish;
return verify_esp_blkid(st.st_dev, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
/* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
* use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
* emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
* however blkid can't work if we have no privileges to access block devices directly, which is why
* we use udev in that case. */
if (unprivileged_mode)
return verify_esp_udev(st.st_dev, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
else
return verify_esp_blkid(st.st_dev, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
finish:
if (ret_part)