Use UDisks to find out if swap devices are encrypted

Using a heuristic is certainly not awesome.
This commit is contained in:
Richard Hughes 2020-10-30 14:56:22 +00:00
parent 2b188c8488
commit 0bdf561035
5 changed files with 209 additions and 12 deletions

View File

@ -2196,8 +2196,14 @@ fu_common_get_block_devices (GError **error)
g_variant_new ("(a{sv})", &builder), g_variant_new ("(a{sv})", &builder),
G_DBUS_CALL_FLAGS_NONE, G_DBUS_CALL_FLAGS_NONE,
-1, NULL, error); -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; return NULL;
}
devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
g_variant_get (output, "(ao)", &iter); g_variant_get (output, "(ao)", &iter);
while (g_variant_iter_next (iter, "&o", &obj)) { 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); 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: * fu_common_get_esp_default:
* @error: A #GError or NULL * @error: A #GError or NULL

View File

@ -238,6 +238,10 @@ gboolean fu_common_is_cpu_intel (void);
gboolean fu_common_is_live_media (void); gboolean fu_common_is_live_media (void);
GPtrArray *fu_common_get_volumes_by_kind (const gchar *kind, GPtrArray *fu_common_get_volumes_by_kind (const gchar *kind,
GError **error); 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, FuVolume *fu_common_get_esp_for_path (const gchar *esp_path,
GError **error); GError **error);
FuVolume *fu_common_get_esp_default (GError **error); FuVolume *fu_common_get_esp_default (GError **error);

View File

@ -672,6 +672,8 @@ LIBFWUPDPLUGIN_1.5.0 {
LIBFWUPDPLUGIN_1.5.1 { LIBFWUPDPLUGIN_1.5.1 {
global: global:
fu_common_get_volume_by_device;
fu_common_get_volume_by_devnum;
fu_device_add_possible_plugin; fu_device_add_possible_plugin;
fu_efivar_space_used; fu_efivar_space_used;
fu_volume_is_encrypted; fu_volume_is_encrypted;

View File

@ -13,46 +13,134 @@
struct _FuLinuxSwap { struct _FuLinuxSwap {
GObject parent_instance; GObject parent_instance;
gboolean encrypted; guint encrypted_cnt;
gboolean enabled; guint enabled_cnt;
}; };
G_DEFINE_TYPE (FuLinuxSwap, fu_linux_swap, G_TYPE_OBJECT) 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 * FuLinuxSwap *
fu_linux_swap_new (const gchar *buf, gsize bufsz, GError **error) fu_linux_swap_new (const gchar *buf, gsize bufsz, GError **error)
{ {
FuLinuxSwap *self = g_object_new (FU_TYPE_LINUX_SWAP, NULL); FuLinuxSwap *self = g_object_new (FU_TYPE_LINUX_SWAP, NULL);
g_auto(GStrv) lines = NULL; g_auto(GStrv) lines = NULL;
/* look at each line in /proc/swaps */
if (bufsz == 0) if (bufsz == 0)
bufsz = strlen (buf); bufsz = strlen (buf);
lines = fu_common_strnsplit (buf, bufsz, "\n", -1); lines = fu_common_strnsplit (buf, bufsz, "\n", -1);
if (g_strv_length (lines) > 2) { if (g_strv_length (lines) > 2) {
self->enabled = TRUE;
for (guint i = 1; lines[i] != NULL && lines[i][0] != '\0'; i++) { for (guint i = 1; lines[i] != NULL && lines[i][0] != '\0'; i++) {
if (g_str_has_prefix (lines[i], "/dev/dm-") || g_autofree gchar *fn = NULL;
g_str_has_prefix (lines[i], "/dev/mapper")) { g_autofree gchar *ty = NULL;
self->encrypted = TRUE;
break; /* 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; return self;
} }
/* success if *all* the swap devices are encrypted */
gboolean gboolean
fu_linux_swap_get_encrypted (FuLinuxSwap *self) fu_linux_swap_get_encrypted (FuLinuxSwap *self)
{ {
g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE); 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 gboolean
fu_linux_swap_get_enabled (FuLinuxSwap *self) fu_linux_swap_get_enabled (FuLinuxSwap *self)
{ {
g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE); g_return_val_if_fail (FU_IS_LINUX_SWAP (self), FALSE);
return self->enabled; return self->enabled_cnt > 0;
} }
static void static void

View File

@ -34,6 +34,14 @@ fu_linux_swap_plain_func (void)
swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" 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); 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_no_error (error);
g_assert_nonnull (swap); g_assert_nonnull (swap);
g_assert_true (fu_linux_swap_get_enabled (swap)); g_assert_true (fu_linux_swap_get_enabled (swap));
@ -49,6 +57,11 @@ fu_linux_swap_encrypted_func (void)
swap = fu_linux_swap_new ("Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n" 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); 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_no_error (error);
g_assert_nonnull (swap); g_assert_nonnull (swap);
g_assert_true (fu_linux_swap_get_enabled (swap)); g_assert_true (fu_linux_swap_get_enabled (swap));