diff --git a/libfwupdplugin/fu-common.c b/libfwupdplugin/fu-common.c index 6b3140898..01b688a08 100644 --- a/libfwupdplugin/fu-common.c +++ b/libfwupdplugin/fu-common.c @@ -2196,8 +2196,14 @@ fu_common_get_block_devices (GError **error) g_variant_new ("(a{sv})", &builder), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); - if (output == NULL) + if (output == NULL) { + if (error != NULL) + g_dbus_error_strip_remote_error (*error); + g_prefix_error (error, "failed to call %s.%s(): ", + UDISKS_DBUS_SERVICE, + "GetBlockDevices"); return NULL; + } devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); g_variant_get (output, "(ao)", &iter); while (g_variant_iter_next (iter, "&o", &obj)) { @@ -2294,6 +2300,90 @@ fu_common_get_volumes_by_kind (const gchar *kind, GError **error) return g_steal_pointer (&volumes); } +/** + * fu_common_get_volume_by_device: + * @device: A device string, typcically starting with `/dev/` + * @error: A #GError or NULL + * + * Finds the first volume from the specified device. + * + * Returns: (transfer full): a #GPtrArray, or %NULL if the kind was not found + * + * Since: 1.5.1 + **/ +FuVolume * +fu_common_get_volume_by_device (const gchar *device, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* find matching block device */ + devices = fu_common_get_block_devices (error); + if (devices == NULL) + return NULL; + for (guint i = 0; i < devices->len; i++) { + GDBusProxy *proxy_blk = g_ptr_array_index (devices, i); + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy_blk, "Device"); + if (val == NULL) + continue; + if (g_strcmp0 (g_variant_get_bytestring (val), device) == 0) { + return g_object_new (FU_TYPE_VOLUME, + "proxy-block", proxy_blk, + NULL); + } + } + + /* failed */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no volumes for device %s", + device); + return NULL; +} + +/** + * fu_common_get_volume_by_devnum: + * @devicenum: A device number + * @error: A #GError or NULL + * + * Finds the first volume from the specified device. + * + * Returns: (transfer full): a #GPtrArray, or %NULL if the kind was not found + * + * Since: 1.5.1 + **/ +FuVolume * +fu_common_get_volume_by_devnum (guint32 devnum, GError **error) +{ + g_autoptr(GPtrArray) devices = NULL; + + /* find matching block device */ + devices = fu_common_get_block_devices (error); + if (devices == NULL) + return NULL; + for (guint i = 0; i < devices->len; i++) { + GDBusProxy *proxy_blk = g_ptr_array_index (devices, i); + g_autoptr(GVariant) val = NULL; + val = g_dbus_proxy_get_cached_property (proxy_blk, "DeviceNumber"); + if (val == NULL) + continue; + if (devnum == g_variant_get_uint64 (val)) { + return g_object_new (FU_TYPE_VOLUME, + "proxy-block", proxy_blk, + NULL); + } + } + + /* failed */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_FOUND, + "no volumes for devnum %u", + devnum); + return NULL; +} + /** * fu_common_get_esp_default: * @error: A #GError or NULL diff --git a/libfwupdplugin/fu-common.h b/libfwupdplugin/fu-common.h index 97c4638ba..8a454fa0d 100644 --- a/libfwupdplugin/fu-common.h +++ b/libfwupdplugin/fu-common.h @@ -238,6 +238,10 @@ gboolean fu_common_is_cpu_intel (void); gboolean fu_common_is_live_media (void); GPtrArray *fu_common_get_volumes_by_kind (const gchar *kind, GError **error); +FuVolume *fu_common_get_volume_by_device (const gchar *device, + GError **error); +FuVolume *fu_common_get_volume_by_devnum (guint32 devnum, + GError **error); FuVolume *fu_common_get_esp_for_path (const gchar *esp_path, GError **error); FuVolume *fu_common_get_esp_default (GError **error); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 31e049d9f..a58bcc015 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -672,6 +672,8 @@ LIBFWUPDPLUGIN_1.5.0 { LIBFWUPDPLUGIN_1.5.1 { global: + fu_common_get_volume_by_device; + fu_common_get_volume_by_devnum; fu_device_add_possible_plugin; fu_efivar_space_used; fu_volume_is_encrypted; diff --git a/plugins/linux-swap/fu-linux-swap.c b/plugins/linux-swap/fu-linux-swap.c index fd7aab915..12e724dc0 100644 --- a/plugins/linux-swap/fu-linux-swap.c +++ b/plugins/linux-swap/fu-linux-swap.c @@ -13,46 +13,134 @@ struct _FuLinuxSwap { GObject parent_instance; - gboolean encrypted; - gboolean enabled; + guint encrypted_cnt; + guint enabled_cnt; }; G_DEFINE_TYPE (FuLinuxSwap, fu_linux_swap, G_TYPE_OBJECT) +static gchar * +fu_strdup_nospaces (const gchar *line) +{ + GString *str = g_string_new (NULL); + for (guint i = 0; line[i] != '\0' && !g_ascii_isspace (line[i]); i++) + g_string_append_c (str, line[i]); + return g_string_free (str, FALSE); +} + +static gboolean +fu_linux_swap_verify_partition (FuLinuxSwap *self, const gchar *fn, GError **error) +{ + g_autoptr(FuVolume) volume = NULL; + + /* find the device */ + volume = fu_common_get_volume_by_device (fn, error); + if (volume == NULL) + return FALSE; + + /* this isn't technically encrypted, but isn't on disk in plaintext */ + if (g_str_has_prefix (fn, "/dev/zram")) { + g_debug ("%s is zram, assuming encrypted", fn); + self->encrypted_cnt++; + return TRUE; + } + + /* is this mount point encrypted */ + if (fu_volume_is_encrypted (volume)) { + g_debug ("%s partition is encrypted", fn); + self->encrypted_cnt++; + } else { + g_debug ("%s partition is unencrypted", fn); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_linux_swap_verify_file (FuLinuxSwap *self, const gchar *fn, GError **error) +{ + guint32 devnum; + g_autoptr(GFile) file = NULL; + g_autoptr(GFileInfo) info = NULL; + g_autoptr(FuVolume) volume = NULL; + + /* get the device number for the file */ + file = g_file_new_for_path (fn); + info = g_file_query_info (file, G_FILE_ATTRIBUTE_UNIX_DEVICE, + G_FILE_QUERY_INFO_NONE, NULL, error); + if (info == NULL) + return FALSE; + devnum = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_DEVICE); + + /* find the device */ + volume = fu_common_get_volume_by_devnum (devnum, error); + if (volume == NULL) + return FALSE; + + /* is this mount point encrypted */ + if (fu_volume_is_encrypted (volume)) { + g_debug ("%s file is encrypted", fn); + self->encrypted_cnt++; + } else { + g_debug ("%s file is unencrypted", fn); + } + + /* success */ + return TRUE; +} + FuLinuxSwap * fu_linux_swap_new (const gchar *buf, gsize bufsz, GError **error) { FuLinuxSwap *self = g_object_new (FU_TYPE_LINUX_SWAP, NULL); g_auto(GStrv) lines = NULL; + /* look at each line in /proc/swaps */ if (bufsz == 0) bufsz = strlen (buf); lines = fu_common_strnsplit (buf, bufsz, "\n", -1); if (g_strv_length (lines) > 2) { - self->enabled = TRUE; for (guint i = 1; lines[i] != NULL && lines[i][0] != '\0'; i++) { - if (g_str_has_prefix (lines[i], "/dev/dm-") || - g_str_has_prefix (lines[i], "/dev/mapper")) { - self->encrypted = TRUE; - break; + g_autofree gchar *fn = NULL; + g_autofree gchar *ty = NULL; + + /* split */ + if (g_utf8_strlen (lines[i], -1) < 45) + continue; + fn = fu_strdup_nospaces (lines[i]); + ty = fu_strdup_nospaces (lines[i] + 40); + + /* partition, so use UDisks to see if backed by crypto */ + if (g_strcmp0 (ty, "partition") == 0) { + self->enabled_cnt++; + if (!fu_linux_swap_verify_partition (self, fn, error)) + return NULL; + } else if (g_strcmp0 (ty, "file") == 0) { + self->enabled_cnt++; + if (!fu_linux_swap_verify_file (self, fn, error)) + return NULL; + } else { + g_warning ("unknown swap type: %s [%s]", ty, fn); } } } return self; } +/* success if *all* the swap devices are encrypted */ gboolean fu_linux_swap_get_encrypted (FuLinuxSwap *self) { g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE); - return self->encrypted; + return self->enabled_cnt > 0 && self->enabled_cnt == self->encrypted_cnt; } gboolean fu_linux_swap_get_enabled (FuLinuxSwap *self) { g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE); - return self->enabled; + return self->enabled_cnt > 0; } static void diff --git a/plugins/linux-swap/fu-self-test.c b/plugins/linux-swap/fu-self-test.c index fccc3f457..3d02805d8 100644 --- a/plugins/linux-swap/fu-self-test.c +++ b/plugins/linux-swap/fu-self-test.c @@ -32,8 +32,16 @@ fu_linux_swap_plain_func (void) g_autoptr(GError) error = NULL; swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" - "/dev/nvme0n1p4 partition\t5962748\t0\t-2\n", + "/dev/nvme0n1p4 partition\t5962748\t0\t-2\n", 0, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { + g_test_skip (error->message); + return; + } + if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { + g_test_skip (error->message); + return; + } g_assert_no_error (error); g_assert_nonnull (swap); g_assert_true (fu_linux_swap_get_enabled (swap)); @@ -47,8 +55,13 @@ fu_linux_swap_encrypted_func (void) g_autoptr(GError) error = NULL; swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" - "/dev/dm-1 partition\t5962748\t0\t-2\n", + "/dev/dm-1 partition\t5962748\t0\t-2\n", 0, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) || + g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { + g_test_skip (error->message); + return; + } g_assert_no_error (error); g_assert_nonnull (swap); g_assert_true (fu_linux_swap_get_enabled (swap));