systemd/0393-udev-restore-syspath-a...

156 lines
6.8 KiB
Diff

From 1f4bc8c496d2a310ffa3e7174af40f7e596cd2d1 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 9 Jan 2023 14:58:58 +0900
Subject: [PATCH] udev: restore syspath and properties on failure
Otherwise, invalid sysname or properties may be broadcast to udev
listeners.
(cherry picked from commit 210033847c340c43dd6835520f21f8b23ba29579)
Related: RHEL-5988
---
src/udev/udev-event.c | 93 +++++++++++++++++++++++++++++--------------
1 file changed, 64 insertions(+), 29 deletions(-)
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 1dc05f863d..fab454ae37 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -906,7 +906,8 @@ static int device_rename(sd_device *device, const char *name) {
}
static int rename_netif(UdevEvent *event) {
- const char *oldname;
+ _cleanup_free_ char *old_syspath = NULL, *old_sysname = NULL;
+ const char *s;
sd_device *dev;
int ifindex, r;
@@ -917,15 +918,6 @@ static int rename_netif(UdevEvent *event) {
dev = ASSERT_PTR(event->dev);
- /* Read sysname from cloned sd-device object, otherwise use-after-free is triggered, as the
- * main object will be renamed and dev->sysname will be freed in device_rename(). */
- r = sd_device_get_sysname(event->dev_db_clone, &oldname);
- if (r < 0)
- return log_device_error_errno(dev, r, "Failed to get sysname: %m");
-
- if (streq(event->name, oldname))
- return 0; /* The interface name is already requested name. */
-
if (!device_for_action(dev, SD_DEVICE_ADD))
return 0; /* Rename the interface only when it is added. */
@@ -933,7 +925,7 @@ static int rename_netif(UdevEvent *event) {
if (r == -ENOENT)
return 0; /* Device is not a network interface. */
if (r < 0)
- return log_device_error_errno(dev, r, "Failed to get ifindex: %m");
+ return log_device_warning_errno(dev, r, "Failed to get ifindex: %m");
if (naming_scheme_has(NAMING_REPLACE_STRICTLY) &&
!ifname_valid(event->name)) {
@@ -941,39 +933,82 @@ static int rename_netif(UdevEvent *event) {
return 0;
}
- /* Set ID_RENAMING boolean property here. It will be dropped when the corresponding move uevent is processed. */
- r = device_add_property(dev, "ID_RENAMING", "1");
+ r = sd_device_get_sysname(dev, &s);
if (r < 0)
- return log_device_warning_errno(dev, r, "Failed to add 'ID_RENAMING' property: %m");
+ return log_device_warning_errno(dev, r, "Failed to get sysname: %m");
- r = device_rename(dev, event->name);
+ if (streq(event->name, s))
+ return 0; /* The interface name is already requested name. */
+
+ old_sysname = strdup(s);
+ if (!old_sysname)
+ return -ENOMEM;
+
+ r = sd_device_get_syspath(dev, &s);
if (r < 0)
- return log_device_warning_errno(dev, r, "Failed to update properties with new name '%s': %m", event->name);
+ return log_device_warning_errno(dev, r, "Failed to get syspath: %m");
+
+ old_syspath = strdup(s);
+ if (!old_syspath)
+ return -ENOMEM;
+
+ r = device_rename(dev, event->name);
+ if (r < 0) {
+ log_device_warning_errno(dev, r, "Failed to update properties with new name '%s': %m", event->name);
+ goto revert;
+ }
+
+ /* Set ID_RENAMING boolean property here. It will be dropped when the corresponding move uevent is processed. */
+ r = device_add_property(dev, "ID_RENAMING", "1");
+ if (r < 0) {
+ log_device_warning_errno(dev, r, "Failed to add 'ID_RENAMING' property: %m");
+ goto revert;
+ }
/* Also set ID_RENAMING boolean property to cloned sd_device object and save it to database
* before calling rtnl_set_link_name(). Otherwise, clients (e.g., systemd-networkd) may receive
* RTM_NEWLINK netlink message before the database is updated. */
r = device_add_property(event->dev_db_clone, "ID_RENAMING", "1");
- if (r < 0)
- return log_device_warning_errno(event->dev_db_clone, r, "Failed to add 'ID_RENAMING' property: %m");
+ if (r < 0) {
+ log_device_warning_errno(event->dev_db_clone, r, "Failed to add 'ID_RENAMING' property: %m");
+ goto revert;
+ }
r = device_update_db(event->dev_db_clone);
- if (r < 0)
- return log_device_debug_errno(event->dev_db_clone, r, "Failed to update database under /run/udev/data/: %m");
+ if (r < 0) {
+ log_device_debug_errno(event->dev_db_clone, r, "Failed to update database under /run/udev/data/: %m");
+ goto revert;
+ }
r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
- if (r == -EBUSY) {
- log_device_info(dev, "Network interface '%s' is already up, cannot rename to '%s'.",
- oldname, event->name);
- return 0;
+ if (r < 0) {
+ if (r == -EBUSY) {
+ log_device_info(dev, "Network interface '%s' is already up, cannot rename to '%s'.",
+ old_sysname, event->name);
+ r = 0;
+ } else
+ log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
+ ifindex, old_sysname, event->name);
+ goto revert;
}
- if (r < 0)
- return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
- ifindex, oldname, event->name);
-
- log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, event->name);
+ log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, old_sysname, event->name);
return 1;
+
+revert:
+ /* Restore 'dev_db_clone' */
+ (void) device_add_property(event->dev_db_clone, "ID_RENAMING", NULL);
+ (void) device_update_db(event->dev_db_clone);
+
+ /* Restore 'dev' */
+ (void) device_set_syspath(dev, old_syspath, /* verify = */ false);
+ if (sd_device_get_property_value(dev, "INTERFACE_OLD", &s) >= 0) {
+ (void) device_add_property_internal(dev, "INTERFACE", s);
+ (void) device_add_property_internal(dev, "INTERFACE_OLD", NULL);
+ }
+ (void) device_add_property(dev, "ID_RENAMING", NULL);
+
+ return r;
}
static int update_devnode(UdevEvent *event) {