At some point the connect command builder was modified, and the
control port over NL80211 check was moved to inside if (is_rsn).
For WPS, no supplicant_ie was set, so CONTROL_PORT_OVER_NL80211
was never set into CMD_CONNECT. This caused IWD to expect WPS
frames over netlink, but the kernel was sending them over the
legacy route.
This commit hardens the iwd.service.in template file for systemd
services. The following is a short explanation for each added directive:
+PrivateTmp=true
If true, sets up a new file system namespace for the executed processes
and mounts private /tmp and /var/tmp directories inside it that is not
shared by processes outside of the namespace.
+NoNewPrivileges=true
If true, ensures that the service process and all its children can never
gain new privileges through execve() (e.g. via setuid or setgid bits, or
filesystem capabilities).
+PrivateDevices=true
If true, sets up a new /dev mount for the executed processes and only
adds API pseudo devices such as /dev/null, /dev/zero or /dev/random (as
well as the pseudo TTY subsystem) to it, but no physical devices such as
/dev/sda, system memory /dev/mem, system ports /dev/port and others.
+ProtectHome=yes
If true, the directories /home, /root and /run/user are made
inaccessible and empty for processes invoked by this unit.
+ProtectSystem=strict
If set to "strict" the entire file system hierarchy is mounted
read-only, except for the API file system subtrees /dev, /proc and /sys
(protect these directories using PrivateDevices=,
ProtectKernelTunables=, ProtectControlGroups=).
+ReadWritePaths=/var/lib/iwd/
Sets up a new file system namespace for executed processes. These
options may be used to limit access a process might have to the file
system hierarchy. Each setting takes a space-separated list of paths
relative to the host's root directory (i.e. the system running the
service manager). Note that if paths contain symlinks, they are resolved
relative to the root directory set with RootDirectory=/RootImage=.
Paths listed in ReadWritePaths= are accessible from within
the namespace with the same access modes as from outside of
it.
+ProtectControlGroups=yes
If true, the Linux Control Groups (cgroups(7)) hierarchies accessible
through /sys/fs/cgroup will be made read-only to all processes of the
unit.
+ProtectKernelModules=yes
If true, explicit module loading will be denied. This allows module
load and unload operations to be turned off on modular kernels.
For further explanation to all directives see `man systemd.directives`
Hostapd has now been updated to include the group number when rejecting
the connection with UNSUPP_FINITE_CYCLIC_GROUP. We still need the existing
len == 0 check because old hostapd versions will still behave this way.
The single-use password is apparently sent in plaintext over the network
but at least try to prevent it from staying in the memory until we know
it's been used.
station.c generates the IEs we will need to use for the
Authenticate/Associate and EAPoL frames and sets them into the
handshake_state object. However the driver may modify some of them
during CMD_CONNECT and we need to use those update values so the AP
isn't confused about differing IEs in diffent frames from us.
Specifically the "wl" driver seems to do this at least for the RSN IE.
The KDF function processes data in 32 byte chunks so for groups which
primes are not divisible by 32 bytes, you will get a buffer overflow
when copying the last chunk of data.
Now l_checksum_get_digest is limited to the bytes remaining in the
buffer, or 32, whichever is the smallest.
Previously, the WPS tests have shared a single instance of iwd
among themselves. This approach didn’t allow to identify which
tests have passed and which failed. The new solution makes WPS
tests independent from each other by creating a new instance
of iwd for each one of them.
Since eapol_encrypt_key_data already calculates the key data length and
encodes it into the key frame, we can just return this length and avoid
having to obtain it again from the frame.
Similar to SAE, EAP-PWD derives an ECC point (PWE). It is possible
for information to be gathered from the timing of this derivation,
which could be used to to recover the password.
This change adapts EAP-PWD to use the same mitigation technique as
SAE where we continue to derive ECC points even after we have found
a valid point. This derivation loop continues for a set number of
iterations (20 in this case), so anyone timing it will always see
the same timings for every run of the protocol.
This is not used by any of the scan notify callback implementations and
for P2P we're going to need to scan on an interface without an ifindex
so without this the other changes should be mostly contained in scan.
Also add a mask parameter to wiphy_get_supported_iftypes to make sure
the SupportedModes property only contains the values that can be used
as Device.Mode.
dbus_iftype_to_string returns NULL for unknown iftypes, the strdup will
also return NULL and ret[i] will be assigned a NULL. As a result
the l_strjoinv will not print the known iftypes that might have come
after that and will the l_strfreev will leak the strduped strings.
sc->state would get set when the TRIGGERED event arrived or when the
triggered callback for our own SCAN_TRIGGER command is received.
However it would not get reset to NOT_RUNNING when the NEW_SCAN_RESULTS
event is received, instead we'd first request the results with GET_SCAN
and only reset sc->state when that returns. If during that command a
new scan gets triggered, the GET_SCAN callback would still reset
sc->state and clobber the value set by the new scan.
To fix that repurpose sc->state to only track that period from the
TRIGGERED signal to the NEW_SCAN_RESULTS signal. sc->triggered can be
used to check if we're still waiting for the GET_SCAN command and
sc->start_cmd_id to check if we're waiting for the scan to get
triggered, so one of these three variables will now always indicate if
a scan is in progress.
We can crash if we abort the connection, but the connect command has
already gone through. In this case we will get a sequence of
authenticate_event, associate_event, connect_event. The first and last
events don't crash since they check whether netdev->connected is true.
However, this causes an annoying warning to be printed.
Fix this by introducing an 'aborting' flag and ignore all connection
related events if it is set.
++++++++ backtrace ++++++++
Now that the OWE failure/retry is handled in netdev, we can catch
all associate error status' inside owe_rx_associate rather than only
catching UNSUPP_FINITE_CYCLIC_GROUP.
Apart from OWE, the association event was disregarded and all association
processing was done in netdev_connect_event. This led to
netdev_connect_event having to handle all the logic of both success and
failure, as well as parsing the association for FT and OWE. Also, without
checking the status code in the associate frame there is the potential
for the kernel to think we are connected even if association failed
(e.g. rogue AP).
This change introduces two flags into netdev, expect_connect_failure and
ignore_connect_event. All the FT processing that was once in
netdev_connect_event has now been moved into netdev_associate_event, as
well as non-FT associate frame processing. The connect event now only
handles failure cases for soft/half MAC cards.
Note: Since fullmac cards rely on the connect event, the eapol_start
and netdev_connect_ok were left in netdev_connect_event. Since neither
auth/assoc events come in on fullmac we shouldn't have any conflict with
the new flags.
Once a connection has completed association, EAPoL is started from
netdev_associate_event (if required) and the ignore_connect_event flag can
be set. This will bypass the connect event.
If a connection has failed during association for whatever reason, we can
set expect_connect_failure, the netdev reason, and the MPDU status code.
This allows netdev_connect_event to both handle the error, and, if required,
send a deauth telling the kernel that we have failed (protecting against the
rogue AP situation).
OWE processing can be completely taken care of inside
netdev_authenticate_event and netdev_associate_event. This removes
the need for OWE specific checks inside netdev_connect_event. We can
now return early out of the connect event if OWE is in progress.
The simplest way to test this was to create a new AP, where
max_num_sta=1. This only allows a single STA to connect to this AP.
We connect a device to this AP, then try and connect with another.
This results in hostapd failing with DENIED_NO_MORE_STAS, which will
cause a temporary blacklist. We can then disconnect both devices,
and reconnect the device that previously got denied. If it connects
then we know the blacklist only persisted for that earlier connection.
Several Auth/Assoc failure status codes indicate that the connection
failed for reasons such as bandwidth issues, poor channel conditions
etc. These conditions should not result in the BSS being blacklisted
since its likely only a temporary issue and the AP is not actually
"broken" per-se.
This adds support in station.c to temporarily blacklist these BSS's
on a per-network basis. After the connection has completed we clear
out these blacklist entries.
Certain error conditions require that a BSS be blacklisted only for
the duration of the current connection. The existing blacklist
does not allow for this, and since this blacklist is shared between
all interfaces it doesnt make sense to use it for this purpose.
Instead, each network object can contain its own blacklist of
scan_bss elements. New elements can be added with network_blacklist_add.
The blacklist is cleared when the connection completes, either
successfully or not.
Now inside network_bss_select both the per-network blacklist as well as
the global blacklist will be checked before returning a BSS.
Several netdev events benefit from including event data in the callback.
This is similar to how the connect callback works as well. The content
of the event data is documented in netdev.h (netdev_event_func_t).
By including event data for the two disconnect events, we can pass the
reason code to better handle the failure in station.c. Now, inside
station_disconnect_event, we still check if there is a pending connection,
and if so we can call the connect callback directly with HANDSHAKE_FAILED.
Doing it this way unifies the code path into a single switch statment to
handle all failures.
In addition, we pass the RSSI level index as event data to
RSSI_LEVEL_NOTIFY. This removes the need for a getter to be exposed in
netdev.h.
On successful send, scan_send_start(..) used to set msg to NULL,
therefore the further management of the command by the caller was
impossible. This patch removes wrapper around l_genl_family_send()
and lets the callers to take responsibility for the command.
This change cleans up the mess of status vs reason codes. The two
types of codes have already been separated into different enumerations,
but netdev was still treating them the same (with last_status_code).
A new 'event_data' argument was added to the connect callback, which
has a different meaning depending on the result of the connection
(described inside netdev.h, netdev_connect_cb_t). This allows for the
removal of netdev_get_last_status_code since the status or reason
code is now passed via event_data.
Inside the netdev object last_status_code was renamed to last_code, for
the purpose of storing either status or reason. This is only used when
a disconnect needs to be emitted before failing the connection. In all
other cases we just pass the code directly into the connect_cb and do
not store it.
All ocurrences of netdev_connect_failed were updated to use the proper
code depending on the netdev result. Most of these simply changed from
REASON_CODE_UNSPECIFIED to STATUS_CODE_UNSPECIFIED. This was simply for
consistency (both codes have the same value).
netdev_[authenticate|associate]_event's were updated to parse the
status code and, if present, use that if their was a failure rather
than defaulting to UNSPECIFIED.