uefi: detect unmounted ESP partitions (Fixes: #1405)

Mount these while writing out updates.
Leave them mounted when done (you gotta reboot anyway).
This commit is contained in:
Mario Limonciello 2019-09-25 15:06:17 -05:00 committed by Mario Limonciello
parent dc227c6037
commit 5bd649ef31
10 changed files with 234 additions and 21 deletions

View File

@ -491,6 +491,7 @@ main (int argc, char **argv)
/* change behaviour */
sysfsdir = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_FW);
g_setenv ("FWUPD_UEFI_ESP_PATH", sysfsdir, TRUE);
g_setenv ("FWUPD_UEFI_TEST", "1", TRUE);
g_setenv ("FWUPD_DELL_FAKE_SMBIOS", "1", FALSE);
/* only critical and error are fatal */

View File

@ -19,6 +19,7 @@
#include "fu-uefi-common.h"
#include "fu-uefi-device.h"
#include "fu-uefi-vars.h"
#include "fu-uefi-udisks.h"
#ifndef HAVE_GIO_2_55_0
#pragma clang diagnostic push
@ -376,6 +377,7 @@ fu_plugin_update (FuPlugin *plugin,
FwupdInstallFlags flags,
GError **error)
{
FuPluginData *data = fu_plugin_get_data (plugin);
const gchar *str;
guint32 flashes_left;
g_autoptr(GError) error_splash = NULL;
@ -403,12 +405,24 @@ fu_plugin_update (FuPlugin *plugin,
/* make sure that the ESP is mounted */
if (g_getenv ("FWUPD_UEFI_ESP_PATH") == NULL) {
if (!fu_plugin_uefi_esp_mounted (plugin, error))
/* mount the partition somewhere */
if (fu_uefi_udisks_objpath (data->esp_path)) {
g_autofree gchar *path = NULL;
path = fu_uefi_udisks_objpath_mount (data->esp_path, error);
if (path == NULL)
return FALSE;
g_debug ("Mounted ESP at %s", path);
g_free (data->esp_path);
data->esp_path = g_strdup (path);
} else if (!fu_plugin_uefi_esp_mounted (plugin, error)) {
return FALSE;
}
}
/* perform the update */
g_debug ("Performing UEFI capsule update");
if (data->esp_path != NULL)
fu_device_set_metadata (device, "EspPath", data->esp_path);
fu_device_set_status (device, FWUPD_STATUS_SCHEDULING);
if (!fu_plugin_uefi_update_splash (plugin, device, &error_splash)) {
g_debug ("failed to upload UEFI UX capsule text: %s",
@ -559,6 +573,10 @@ fu_plugin_uefi_delete_old_capsules (FuPlugin *plugin, GError **error)
g_autofree gchar *pattern = NULL;
g_autoptr(GPtrArray) files = NULL;
/* can only do this if we're mounted */
if (fu_uefi_udisks_objpath (data->esp_path))
return TRUE;
/* delete any files matching the glob in the ESP */
files = fu_common_get_files_recursive (data->esp_path, error);
if (files == NULL)
@ -677,16 +695,10 @@ fu_plugin_uefi_ensure_esp_path (FuPlugin *plugin, GError **error)
g_ascii_strcasecmp (require_shim_for_sb, "true") == 0)
data->require_shim_for_sb = TRUE;
/* try to guess from heuristics */
data->esp_path = fu_uefi_guess_esp_path ();
if (data->esp_path == NULL) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_FILENAME,
"Unable to determine EFI system partition location, "
"See https://github.com/fwupd/fwupd/wiki/Determining-EFI-system-partition-location");
/* try to guess from heuristics and partitions */
data->esp_path = fu_uefi_guess_esp_path (error);
if (data->esp_path == NULL)
return FALSE;
}
/* check free space */
if (!fu_uefi_check_esp_free_space (data->esp_path, sz_reqd, error))

View File

@ -303,7 +303,7 @@ fu_uefi_bootmgr_bootnext (const gchar *esp_path,
g_autofree gchar *target_app = NULL;
/* skip for self tests */
if (g_getenv ("FWUPD_UEFI_ESP_PATH") != NULL)
if (g_getenv ("FWUPD_UEFI_TEST") != NULL)
return TRUE;
/* if secure boot was turned on this might need to be installed separately */

View File

@ -13,6 +13,7 @@
#include "fu-common.h"
#include "fu-uefi-common.h"
#include "fu-uefi-vars.h"
#include "fu-uefi-udisks.h"
#include "fwupd-common.h"
#include "fwupd-error.h"
@ -277,6 +278,10 @@ fu_uefi_check_esp_free_space (const gchar *path, guint64 required, GError **erro
g_autoptr(GFile) file = NULL;
g_autoptr(GFileInfo) info = NULL;
/* skip the checks for unmounted disks */
if (fu_uefi_udisks_objpath (path))
return TRUE;
file = g_file_new_for_path (path);
info = g_file_query_filesystem_info (file,
G_FILE_ATTRIBUTE_FILESYSTEM_FREE,
@ -351,8 +356,45 @@ fu_uefi_check_esp_path (const gchar *path, GError **error)
return TRUE;
}
static gchar *
fu_uefi_probe_for_esp (GError **error)
{
g_autoptr(GPtrArray) devices = NULL;
g_autofree gchar *found_esp = NULL;
devices = fu_uefi_udisks_get_block_devices (error);
if (devices == NULL)
return FALSE;
for (guint i = 0; i < devices->len; i++) {
const gchar *obj = g_ptr_array_index (devices, i);
gboolean esp = fu_uefi_udisks_objpath_is_esp (obj);
g_debug ("block device %s, is_esp: %d", obj, esp);
if (!esp)
continue;
if (found_esp != NULL) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_FILENAME,
"Multiple EFI system partitions found, "
"See https://github.com/fwupd/fwupd/wiki/Determining-EFI-system-partition-location");
return NULL;
}
found_esp = g_strdup (obj);
}
if (found_esp == NULL) {
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_FILENAME,
"Unable to determine EFI system partition location, "
"See https://github.com/fwupd/fwupd/wiki/Determining-EFI-system-partition-location");
return NULL;
}
return g_steal_pointer (&found_esp);
}
gchar *
fu_uefi_guess_esp_path (void)
fu_uefi_guess_esp_path (GError **error)
{
const gchar *paths[] = {"/boot/efi", "/boot", "/efi", NULL};
const gchar *path_tmp;
@ -362,16 +404,19 @@ fu_uefi_guess_esp_path (void)
if (path_tmp != NULL)
return g_strdup (path_tmp);
/* try to use known paths */
for (guint i = 0; paths[i] != NULL; i++) {
g_autoptr(GError) error = NULL;
if (!fu_uefi_check_esp_path (paths[i], &error)) {
g_debug ("ignoring ESP path: %s", error->message);
g_autoptr(GError) error_local = NULL;
if (!fu_uefi_check_esp_path (paths[i], &error_local)) {
g_debug ("ignoring ESP path: %s", error_local->message);
continue;
}
return g_strdup (paths[i]);
}
return NULL;
/* prove udisks2 */
g_debug ("Using UDisks2 to probe for ESP");
return fu_uefi_probe_for_esp (error);
}
gboolean

View File

@ -72,7 +72,7 @@ gboolean fu_uefi_get_framebuffer_size (guint32 *width,
guint32 *height,
GError **error);
gboolean fu_uefi_secure_boot_enabled (void);
gchar *fu_uefi_guess_esp_path (void);
gchar *fu_uefi_guess_esp_path (GError **error);
gboolean fu_uefi_check_esp_path (const gchar *path,
GError **error);
gboolean fu_uefi_check_esp_free_space (const gchar *path,

View File

@ -363,7 +363,7 @@ fu_uefi_device_write_update_info (FuUefiDevice *self,
};
/* set the body as the device path */
if (g_getenv ("FWUPD_UEFI_ESP_PATH") != NULL) {
if (g_getenv ("FWUPD_UEFI_TEST") != NULL) {
g_debug ("not building device path, in tests....");
return TRUE;
}

View File

@ -164,10 +164,11 @@ main (int argc, char *argv[])
return EXIT_FAILURE;
}
} else {
esp_path = fu_uefi_guess_esp_path ();
g_autoptr(GError) error_local = NULL;
esp_path = fu_uefi_guess_esp_path (&error_local);
if (esp_path == NULL) {
g_printerr ("Unable to determine EFI system partition "
"location, override using --esp-path\n");
g_printerr ("%s: override using --esp-path\n",
error_local->message);
return EXIT_FAILURE;
}
}

View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2019 Mario Limonciello <mario.limonciello@dell.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <gio/gio.h>
#include "fu-uefi-udisks.h"
#include "fwupd-common.h"
#include "fwupd-error.h"
#define UDISKS_DBUS_SERVICE "org.freedesktop.UDisks2"
#define UDISKS_DBUS_PATH "/org/freedesktop/UDisks2/Manager"
#define UDISKS_DBUS_MANAGER_INTERFACE "org.freedesktop.UDisks2.Manager"
#define UDISKS_DBUS_PART_INTERFACE "org.freedesktop.UDisks2.Partition"
#define UDISKS_DBUS_FILE_INTERFACE "org.freedesktop.UDisks2.Filesystem"
#define ESP_DISK_TYPE "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"
gboolean
fu_uefi_udisks_objpath (const gchar *path)
{
return g_str_has_prefix (path, "/org/freedesktop/UDisks2/");
}
static GDBusProxy *
fu_uefi_udisks_get_dbus_proxy (const gchar *path, const gchar *interface,
GError **error)
{
g_autoptr(GDBusConnection) connection = NULL;
g_autoptr(GDBusProxy) proxy = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error);
if (connection == NULL) {
g_prefix_error (error, "failed to get bus: ");
return NULL;
}
proxy = g_dbus_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE, NULL,
UDISKS_DBUS_SERVICE,
path,
interface,
NULL, error);
if (proxy == NULL) {
g_prefix_error (error, "failed to find %s: ", UDISKS_DBUS_SERVICE);
return NULL;
}
return g_steal_pointer (&proxy);
}
GPtrArray *
fu_uefi_udisks_get_block_devices (GError **error)
{
g_autoptr(GVariant) output = NULL;
g_autoptr(GDBusProxy) proxy = NULL;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GVariantIter) iter = NULL;
GVariant *input;
GVariantBuilder builder;
const gchar *obj;
proxy = fu_uefi_udisks_get_dbus_proxy (UDISKS_DBUS_PATH,
UDISKS_DBUS_MANAGER_INTERFACE,
error);
if (proxy == NULL)
return NULL;
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
input = g_variant_new ("(a{sv})", &builder);
output = g_dbus_proxy_call_sync (proxy,
"GetBlockDevices", g_variant_ref (input),
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, error);
if (output == NULL)
return FALSE;
devices = g_ptr_array_new_with_free_func (g_free);
g_variant_get (output, "(ao)", &iter);
while (g_variant_iter_next (iter, "o", &obj))
g_ptr_array_add (devices, g_strdup (obj));
return g_steal_pointer (&devices);
}
gboolean
fu_uefi_udisks_objpath_is_esp (const gchar *obj)
{
g_autoptr(GDBusProxy) proxy = NULL;
g_autoptr(GError) error_local = NULL;
g_autoptr(GVariant) val = NULL;
const gchar *str;
proxy = fu_uefi_udisks_get_dbus_proxy (obj,
UDISKS_DBUS_PART_INTERFACE,
&error_local);
if (proxy == NULL) {
g_warning ("Failed to initialize d-bus proxy: %s",
error_local->message);
return FALSE;
}
val = g_dbus_proxy_get_cached_property (proxy, "Type");
if (val == NULL)
return FALSE;
g_variant_get (val, "s", &str);
return g_strcmp0 (str, ESP_DISK_TYPE) == 0;
}
gchar *
fu_uefi_udisks_objpath_mount (const gchar *path, GError **error)
{
GVariant *input;
GVariantBuilder builder;
const gchar *str;
g_autoptr(GDBusProxy) proxy = NULL;
g_autoptr(GVariant) val = NULL;
g_return_val_if_fail (fu_uefi_udisks_objpath (path), NULL);
proxy = fu_uefi_udisks_get_dbus_proxy (path,
UDISKS_DBUS_FILE_INTERFACE,
error);
if (proxy == NULL)
return NULL;
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
input = g_variant_new ("(a{sv})", &builder);
val = g_dbus_proxy_call_sync (proxy,
"Mount", input,
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, error);
if (val == NULL)
return NULL;
g_variant_get (val, "(s)", &str);
return g_strdup (str);
}

View File

@ -0,0 +1,13 @@
/*
* Copyright (C) 2019 Mario Limonciello <mario.limonciello@dell.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
GPtrArray *fu_uefi_udisks_get_block_devices (GError **error);
gboolean fu_uefi_udisks_objpath (const gchar *path);
gboolean fu_uefi_udisks_objpath_is_esp (const gchar *obj);
gchar *fu_uefi_udisks_objpath_mount (const gchar *path,
GError **error);

View File

@ -23,6 +23,7 @@ shared_module('fu_plugin_uefi',
'fu-uefi-devpath.c',
'fu-uefi-pcrs.c',
'fu-uefi-update-info.c',
'fu-uefi-udisks.c',
'fu-uefi-vars.c',
],
include_directories : [
@ -58,6 +59,7 @@ executable(
'fu-uefi-devpath.c',
'fu-uefi-pcrs.c',
'fu-uefi-update-info.c',
'fu-uefi-udisks.c',
'fu-uefi-vars.c',
],
include_directories : [
@ -102,6 +104,7 @@ if get_option('tests')
'fu-uefi-pcrs.c',
'fu-uefi-update-info.c',
'fu-uefi-vars.c',
'fu-uefi-udisks.c',
'fu-ucs2.c',
],
include_directories : [