iwd: Validate UTF-8 SSID early in check_connection_compatible/complete_connection

IWD only supports UTF-8 SSIDs internally, any BSS who's SSID doesn't
validate as UTF-8 is ignored.  There's also no way to ask IWD to connect
to such network/start AP/Adhoc etc. because SSIDs are passed as D-Bus
strings.  So validate that connection SSIDs are UTF-8 early in
check_connection_compatible/complete_connection and refactor
check_connection slightly to avoid duplication.

Since NMWifiAPs are created by us, we already know those have valid
SSIDs so once we've also checked new NMConnections in
check_connection_compatible there should be no possibility that an SSID
anywhere else in the code is not UTF8.  We should be able to treat the
GBytes values as UTF8 without redundant validation or the complex
locale-dependent conversions in _nm_utils_ssid_to_utf8.
This commit is contained in:
Andrew Zaborowski 2020-10-23 20:13:01 +02:00 committed by Thomas Haller
parent ca820d5f65
commit 7cc5ee473e
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728

View file

@ -656,6 +656,9 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
const char * mode; const char * mode;
NMIwdNetworkSecurity security; NMIwdNetworkSecurity security;
gboolean mapped; gboolean mapped;
GBytes * ssid;
const guint8 * ssid_bytes;
gsize ssid_len;
if (!NM_DEVICE_CLASS(nm_device_iwd_parent_class) if (!NM_DEVICE_CLASS(nm_device_iwd_parent_class)
->check_connection_compatible(device, connection, error)) ->check_connection_compatible(device, connection, error))
@ -663,6 +666,23 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
s_wireless = nm_connection_get_setting_wireless(connection); s_wireless = nm_connection_get_setting_wireless(connection);
/* complete_connection would be called (if at all) before this function
* so an SSID should always be set. IWD doesn't support non-UTF8 SSIDs
* (ignores BSSes with such SSIDs and has no way to represent them on
* DBus) so we can cut it short for connections with a non-UTF8 SSID.
*/
ssid = nm_setting_wireless_get_ssid(s_wireless);
if (!ssid)
return FALSE;
ssid_bytes = g_bytes_get_data(ssid, &ssid_len);
if (!g_utf8_validate((const char *) ssid_bytes, ssid_len, NULL)) {
nm_utils_error_set_literal(error,
NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
"non-UTF-8 connection SSID not supported by IWD backend");
return FALSE;
}
perm_hw_addr = nm_device_get_permanent_hw_address(device); perm_hw_addr = nm_device_get_permanent_hw_address(device);
mac = nm_setting_wireless_get_mac_address(s_wireless); mac = nm_setting_wireless_get_mac_address(s_wireless);
if (perm_hw_addr) { if (perm_hw_addr) {
@ -862,20 +882,18 @@ complete_connection(NMDevice * device,
NMSettingWireless * s_wifi; NMSettingWireless * s_wifi;
gs_free char * ssid_utf8 = NULL; gs_free char * ssid_utf8 = NULL;
NMWifiAP * ap; NMWifiAP * ap;
GBytes * ssid; GBytes * ssid = NULL;
GBytes * setting_ssid = NULL; gboolean hidden = FALSE;
gboolean hidden = FALSE;
const char * mode; const char * mode;
s_wifi = nm_connection_get_setting_wireless(connection); s_wifi = nm_connection_get_setting_wireless(connection);
mode = s_wifi ? nm_setting_wireless_get_mode(s_wifi) : NULL; mode = s_wifi ? nm_setting_wireless_get_mode(s_wifi) : NULL;
if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_AP)) { if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_AP) || !specific_object) {
if (!nm_setting_verify(NM_SETTING(s_wifi), connection, error)) const guint8 *ssid_bytes;
return FALSE; gsize ssid_len;
ap = NULL;
} else if (!specific_object) {
/* If not given a specific object, we need at minimum an SSID */ /* If not given a specific object, we need at minimum an SSID */
if (!s_wifi) { if (!s_wifi) {
g_set_error_literal(error, g_set_error_literal(error,
@ -885,16 +903,24 @@ complete_connection(NMDevice * device,
return FALSE; return FALSE;
} }
setting_ssid = nm_setting_wireless_get_ssid(s_wifi); ssid = nm_setting_wireless_get_ssid(s_wifi);
if (!setting_ssid || g_bytes_get_size(setting_ssid) == 0) { ssid_bytes = g_bytes_get_data(ssid, &ssid_len);
g_set_error_literal(
error, if (!ssid || ssid_len == 0 || !g_utf8_validate((const char *) ssid_bytes, ssid_len, NULL)) {
NM_DEVICE_ERROR, g_set_error_literal(error,
NM_DEVICE_ERROR_INVALID_CONNECTION, NM_DEVICE_ERROR,
"A 'wireless' setting with a valid SSID is required if no AP path was given."); NM_DEVICE_ERROR_INVALID_CONNECTION,
"A 'wireless' setting with a valid UTF-8 SSID is required if no AP "
"path was given.");
return FALSE; return FALSE;
} }
}
if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_AP)) {
if (!nm_setting_verify(NM_SETTING(s_wifi), connection, error))
return FALSE;
ap = NULL;
} else if (!specific_object) {
/* Find a compatible AP in the scan list */ /* Find a compatible AP in the scan list */
ap = nm_wifi_aps_find_first_compatible(&priv->aps_lst_head, connection); ap = nm_wifi_aps_find_first_compatible(&priv->aps_lst_head, connection);
if (!ap) { if (!ap) {
@ -923,24 +949,14 @@ complete_connection(NMDevice * device,
specific_object); specific_object);
return FALSE; return FALSE;
} }
}
/* Add a wifi setting if one doesn't exist yet */
if (!s_wifi) {
s_wifi = (NMSettingWireless *) nm_setting_wireless_new();
nm_connection_add_setting(connection, NM_SETTING(s_wifi));
}
ssid = nm_setting_wireless_get_ssid(s_wifi);
if (!ssid && ap)
ssid = nm_wifi_ap_get_ssid(ap); ssid = nm_wifi_ap_get_ssid(ap);
if (!ssid) { /* Add a wifi setting if one doesn't exist yet */
g_set_error_literal(error, if (!s_wifi) {
NM_DEVICE_ERROR, s_wifi = (NMSettingWireless *) nm_setting_wireless_new();
NM_DEVICE_ERROR_INVALID_CONNECTION, nm_connection_add_setting(connection, NM_SETTING(s_wifi));
"A 'wireless' setting with a valid SSID is required."); }
return FALSE;
} }
if (ap) { if (ap) {