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:
parent
ad95aa44d6
commit
cedb9eec76
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue