fix: Refine MAC validation using interface name

When a user provides both an interface name and a MAC address, the
current validation process retrieves sysfs link info separately using
the interface name and the MAC address, then compares the results. If
the information doesn't match, an error is raised.

However, this approach may trigger false alarms because retrieving the
link info by MAC might return the link info that only matches the
current MAC instead of the permanent MAC. Since the interface name is
unique within the kernel, a more robust validation method is to fetch
the MAC address using the interface name and then compare it directly
with the user-provided MAC address.

Resolves: https://issues.redhat.com/browse/RHEL-84362

Signed-off-by: Wen Liang <liangwen12year@gmail.com>
This commit is contained in:
Wen Liang 2025-03-10 15:29:15 -04:00 committed by liangwen12year
parent cac2bbb43e
commit fe7c6c6fd5
5 changed files with 129 additions and 9 deletions

View file

@ -95,6 +95,7 @@ ABSENT_STATE = "absent"
DEFAULT_ACTIVATION_TIMEOUT = 90
DEFAULT_TIMEOUT = 10
NULL_MAC = "00:00:00:00:00:00"
class CheckMode:
@ -166,6 +167,20 @@ class SysUtil:
c = SysUtil._sysctl_read("/sys/class/net/" + ifname + "/address")
return Util.mac_norm(c.strip())
@staticmethod
def _link_read_bond_port_perm_hwaddr(ifname):
filename = os.path.join(
"/sys/class/net",
ifname,
# wokeignore:rule=slave
"bonding_slave",
"perm_hwaddr",
)
if not os.path.exists(filename):
return None
c = SysUtil._sysctl_read(filename)
return Util.mac_norm(c.strip())
@staticmethod
def _link_read_permaddress(ifname):
return ethtool.get_perm_addr(ifname)
@ -186,6 +201,13 @@ class SysUtil:
"ifname": ifname,
"address": SysUtil._link_read_address(ifname),
"perm-address": SysUtil._link_read_permaddress(ifname),
# When an interface is added as a port of a bonding device, its MAC
# address might change, we need to retrieve and preserve the original
# MAC address to ensure the user-provided interface name and MAC match
# correctly.
"bond-port-perm-hwaddr": SysUtil._link_read_bond_port_perm_hwaddr(
ifname
),
}
return links
@ -2130,14 +2152,13 @@ class Cmd(object):
for idx, connection in enumerate(self.connections):
if "type" in connection and connection["check_iface_exists"]:
# when the profile is tied to a certain interface via
# 'interface_name' or 'mac', check that such an interface
# 'interface_name' and 'mac', check that such an interface
# exists.
#
# This check has many flaws, as we don't check whether the
# existing interface has the right device type. Also, there is
# some ambiguity between the current MAC address and the
# permanent MAC address.
li_mac = None
li_ifname = None
if connection["interface_name"]:
li_ifname = SysUtil.link_info_find(connection["interface_name"])
@ -2156,13 +2177,23 @@ class Cmd(object):
"infiniband interface exists"
% (connection["interface_name"]),
)
if li_mac and li_ifname and li_mac != li_ifname:
self.log_fatal(
idx,
"profile specifies interface_name '%s' and mac '%s' but no "
"such interface exists"
% (connection["interface_name"], connection["mac"]),
)
elif connection["mac"]:
perm_address = li_ifname.get("perm-address", NULL_MAC)
current_address = li_ifname.get("address", NULL_MAC)
bond_port_perm_hwaddr = li_ifname.get(
"bond-port-perm-hwaddr", NULL_MAC
)
if (perm_address not in (NULL_MAC, connection["mac"])) or (
perm_address == NULL_MAC
and connection["mac"]
not in (current_address, bond_port_perm_hwaddr)
):
self.log_fatal(
idx,
"profile specifies interface_name '%s' and mac '%s' "
"but no such interface exists"
% (connection["interface_name"], connection["mac"]),
)
def start_transaction(self):
"""Hook before making changes"""