Commit graph

34335 commits

Author SHA1 Message Date
Beniamino Galvani
c0d5e9ab91 bpf: clat: change the signature of update_icmp_checksum()
- rename argument 'add' to 'v4to6'
- make argument 'ip6h' const since it's not modified by the function
2025-12-17 18:52:08 +01:00
Beniamino Galvani
6a1f5a764e bpf: clat: remove unused variables 2025-12-17 18:52:06 +01:00
Beniamino Galvani
6e9c6e1669 clat: pass the configuration as struct
The program only needs to know the local IPv4 address, the local IPv6
address and the PREF64. There is no need to create multiple maps for
that, just pass a configuration struct containing those 3 fields.
2025-12-17 18:52:05 +01:00
Beniamino Galvani
195d6e5561 clat: remove the libxdp dependency
It's no longer required
2025-12-17 18:52:04 +01:00
Beniamino Galvani
6085095101 bpf: clat: rework to avoid pointer arithmetic
Avoid using pointer arithmetic in the BPF program, so that it requires
only CAP_BPF and not CAP_PERFMON. In this context "pointer arithmetic"
means adding a variable value to a packet pointer. This means that the
program no longer tries to parse variable-size headers (IPv4 options,
IPv6 extension headers). Those were already not supported before. It
also doesn't parse VLAN tags, but there should be no need for that. If
we use fixed offset, we can avoid using the parsing helpers from
libxdp.
2025-12-17 18:52:03 +01:00
Beniamino Galvani
48be1b549e ipv4: improve logging for ipv4.dhcp-ipv6-only-preferred 2025-12-17 18:52:02 +01:00
Beniamino Galvani
bf8c9551b8 ipv4: enable by default ipv4.dhcp-ipv6-only-preferred when CLAT is on 2025-12-17 18:52:01 +01:00
Mary Strodl
3d400e3592 NEWS: Note CLAT support 2025-12-17 18:51:59 +01:00
Beniamino Galvani
930b035118 bpf: clat: remove commented code
The rewrite of IPv6 header inside a ICMP error needs to be
implemented. Remove the unused comments for now.
2025-12-17 18:51:59 +01:00
Beniamino Galvani
1aa9bc1f5e bpf: clat: fix error handling for IPv6 packets
There are 3 possible results from clat_translate_v6():

 1. the packet didn't match the CLAT IPv6 address and must be
   accepted;

 2. the packet matches but it is invalid and so it must be dropped;

 3. the packet matches and it is valid; clat_handle_v6() should
    translate the packet to IPv4;

Before, the function returned TC_ACT_SHOT for both 2 and 3. Therefore,
clat_handle_v6() tried to rewrite also invalid packets.

Fix that by returning TC_ACT_UNSPEC for valid packets, meaning that
there isn't a final verdict yet.
2025-12-17 18:51:58 +01:00
Beniamino Galvani
25158ac7e6 bpf: clat: don't explicitly inline functions
BPF handles function calls fine these days.
2025-12-17 18:51:57 +01:00
Beniamino Galvani
acfa0ab3a3 bpf: clat: fix other verifier errors 2025-12-17 18:51:56 +01:00
Beniamino Galvani
d44e21c62c bpf: clat: avoid 32-bit register spills when access skb->data
The verifier reports this error when accessing skb->data:

  ; void *data     = (void *)(unsigned long long)skb->data; @ clat.bpf.c:625
  (61) r2 = *(u32 *)(r1 +76)       ; frame1: R1=ctx() R2_w=pkt(r=0)
  (63) *(u32 *)(r10 -120) = r2
  invalid size of register spill

Apparently it's trying to spill only 32 bits from the register to the
stack, which is invalid. A similar problem was reported here:
https://github.com/cilium/cilium/pull/25336

Add some macros using inline asm to fix the problem. With this change
now the compiler properly generates 64-bit spills.

 ; src/core/bpf/clat.bpf.c:625
-;     void *data     = (void *)(unsigned long long)skb->data;
+;     void *data     = SKB_DATA(skb);
      137:      61 12 4c 00 00 00 00 00 w2 = *(u32 *)(r1 + 0x4c)
-     138:      63 2a 88 ff 00 00 00 00 *(u32 *)(r10 - 0x78) = w2
+     138:      7b 2a 88 ff 00 00 00 00 *(u64 *)(r10 - 0x78) = r2
2025-12-17 18:51:56 +01:00
Beniamino Galvani
32d17d4ce6 core: honor the ipv6.clat property 2025-12-17 18:51:55 +01:00
Beniamino Galvani
e097b33e22 libnm,nmcli: add a ipv6.clat property 2025-12-17 18:37:14 +01:00
Beniamino Galvani
0551f38b83 ndisc: add support for PREF64 option (fixes) 2025-12-17 18:31:17 +01:00
Mary Strodl
1c72b3f252 ndisc: add support for PREF64 option 2025-12-17 18:31:16 +01:00
Beniamino Galvani
6395de653c Add support for CLAT to l3cfg (fixes) 2025-12-17 18:31:15 +01:00
Mary Strodl
e262c84032 Add support for CLAT to l3cfg 2025-12-17 18:31:14 +01:00
Beniamino Galvani
3919f06e98 Add CLAT BPF program and build machinery (fixes) 2025-12-17 18:31:13 +01:00
Mary Strodl
b75c247b6d Add CLAT BPF program and build machinery 2025-12-17 18:31:12 +01:00
Mary Strodl
503673cab3 contrib: Add libbpf and libxdp to dependencies
Required for CLAT support
2025-12-17 18:31:12 +01:00
Mary Strodl
a6be193490 l3-config-data: make get_direct_route_for_host public 2025-12-17 18:31:11 +01:00
Mary Strodl
fd4cd2a7ed clat: propagate network_id down to l3cfg 2025-12-17 18:31:10 +01:00
Beniamino Galvani
a5cc5a7539 netns: add a CLAT IP reservation type
This will be used to obtain an IPv4 address to be used for the CLAT
(464XLAT).

Based on a patch by Mary Strodl <ipadlover8322@gmail.com>.
2025-12-17 18:31:10 +01:00
Beniamino Galvani
a2d147366c Merge branch 'bg/issue1688'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2323
2025-12-17 11:59:20 +01:00
Beniamino Galvani
427a7cf257 nmcli: start the agent only after updating the connection
When connecting to a wifi network and providing the password on the
command line, nmcli first looks if there is a compatible connection to
reuse. If there is not, it creates and activates a new one via a
single call to AddAndActivate().

If there is a compatible connection, nmcli first calls Update() on it
to set the new password and then Activate() to bring it up. Before
that, it registers a secret agent that can prompt for a new password
in case of authentication failure.

However, as soon as nmcli registers a secret agent, NM tries to
activate again the connection if it was blocked due to a previous
authentication failure. This connection attempt is going to fail
because it still uses the old password, as new one hasn't been set via
Update().

Change the order of operations to register the agent after Update()
and before Activate().

Reproducer:

 nmcli device wifi connect SSID password BAD_PASSWORD
 nmcli device wifi connect SSID password GOOD_PASSWORD

Fixes: c8ff1b30fb ('nmcli/dev: use secret agent for nmcli d [wifi] connect')
2025-12-17 10:55:51 +01:00
Beniamino Galvani
3a4e18e302 nmcli: fix "device wifi connect" command with existing connection
Executing this command twice, or when a connection profile already
exists for the SSID:

  nmcli device wifi connect $SSID password $PASSWORD

returns error:

  Error: 802-11-wireless-security.key-mgmt: property is missing.

When setting the password nmcli was wiping the existing wireless
security setting.

Fixes: c8ff1b30fb ('nmcli/dev: use secret agent for nmcli d [wifi] connect')

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1688
2025-12-17 10:55:50 +01:00
Íñigo Huguet
8e0825f9cd release: bump version to 1.57.1 (development) 2025-12-12 16:01:44 +01:00
Íñigo Huguet
df8288de7f merge: branch 'ih/strerror_r'
Fix two compilation issues

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2330
2025-12-12 14:36:58 +00:00
Íñigo Huguet
118475d571 ci: build with -D systemdsystemgeneratordir=no
Avoid build failures in some distros.
  ERROR: Assert failed: systemd required but not found, please provide a valid systemd user generator dir or disable it

Fixes: 636fb5ef24 ('systemd: install initrd services using a generator')
2025-12-12 15:24:09 +01:00
Íñigo Huguet
599cc1ed1d std-aux: use _nm_strerror_r
The function strerror_r returns an int per POSIX spec, but GNU version
returns char *. Using it fails the compilation in Alpine, so use
_nm_strerror_r instead that handles both cases.

Fixes: 41e28b900f ('daemon-helper: add read-file-as-user')
2025-12-12 15:07:53 +01:00
Íñigo Huguet
1756ec54e3 merge: branch 'issue1809'
CVE-2025-9615: avoid that non-admin user using other users' certificates.

Closes #1809

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2324
2025-12-12 12:29:41 +00:00
Beniamino Galvani
1a52bbe7c9 libnm: add function to copy a certificate or key as user
Add a new public function nm_utils_copy_cert_as_user() to libnm. It
reads a certificate or key file on behalf of the given user and writes
it to a directory in /run/NetworkManager. It is useful for VPN plugins
that run as root and need to verify that the user owning the
connection (the one listed in the connection.permissions property) can
access the file.
2025-12-12 12:43:15 +01:00
Beniamino Galvani
57eb4a5bc6 vpn: check that plugin supports private connections
Only allow private VPN connections if the VPN plugin declares the
supports-safe-private-file-access capability. Also check that the
private connection doesn't have more than one owner.
2025-12-12 12:42:01 +01:00
Beniamino Galvani
10db4baeb6 vpn: add nm_vpn_plugin_info_supports_safe_private_file_access()
The new API indicates that the VPN plugin supports reading files
(certificates, keys) of private connections in a safe way
(i.e. checking user permissions), or that it doesn't need to read any
file from disk.
2025-12-12 12:41:28 +01:00
Beniamino Galvani
8d8edda3f4 core,libnm-core: introduce property flag for certificate and keys
If we add a new property in the future and it references a certificate
or key stored on disk, we need to also implement the logic to verify
the access to the file for private connections.

Add a new property flag NM_SETTING_PARAM_CERT_KEY_FILE to existing
certificate and key properties, so that it's easier to see that they
need special treatment. Also add some assertions to verify that the
properties with the flag are handled properly.

While at it, move the enumeration of private-files to the settings.
2025-12-12 12:38:50 +01:00
Beniamino Galvani
e85cc46d0b core: pass certificates as blobs to supplicant for private connections
In case of private connections, the device has already read the
certificates and keys content from disk, validating that the owner of
the connection has access to them. Pass those files as blobs to the
supplicant so that it doesn't have to read them again from the
filesystem, creating the opportunity for TOCTOU bugs.
2025-12-12 12:38:50 +01:00
Beniamino Galvani
a1928b4459 device: read private files in stage2
During stage2 (prepare) of an activation, check if the connection is
private and if it contains any certificate/key path. If so, start
reading the files and delay stage2. Once done, store the files'
content into priv->private_files.table and continue the activation.
2025-12-12 12:38:49 +01:00
Beniamino Galvani
9703305122 core: add functions to read private files of connections
Add function nm_utils_read_private_files(). It can be used to read a
list of paths as the given user. It spawns the daemon-helper to read
each path and returns asynchronously a hash table containing the files
content.

Also add nm_utils_get_connection_private_files_paths() to return a
list of file paths referenced in a connection. The function currently
returns only 802.1x file paths for certificates and keys.
2025-12-12 12:38:49 +01:00
Beniamino Galvani
932b85f7e7 supplicant: rename variables
Rename uid to to blob_id, and con_uid to con_uuid.
2025-12-12 12:38:49 +01:00
Beniamino Galvani
4e26403c4a core: support returning binary output from the daemon helper
The full output of the daemon helper is added to a NMStrBuf, without
interpreting it as a string (that is, without stopping at the first
NUL character).

However, when we retrieve the content from the NMStrBuf we assume it's
a string. This is fine for certain commands that expect a string
output, but it's not for other commands as the read-file-as-user one.

Add a new argument to nm_utils_spawn_helper() to specify whether the
output is binary or not. Also have different finish functions
depending on the return type.
2025-12-12 12:38:49 +01:00
Beniamino Galvani
bd2484d1a9 supplicant: remove blobs before adding new ones
When connecting, we add the blobs to the Interface object of the
supplicant. Those blobs are not removed on disconnect and so when we
try to add blobs with the same id, the supplicant returns an error.

Make sure we start from a clean slate on each connection attempt, by
deleting all existing blobs. Probably we should also delete the added
blobs on disconnect, but that's left for a future improvement.
2025-12-12 12:38:48 +01:00
Beniamino Galvani
41e28b900f daemon-helper: add read-file-as-user
Add a new command to read the content of a file after switching to the
given user. This command can be used to enforce Unix filesystem
permissions when accessing a file on behalf of a user.
2025-12-12 12:38:48 +01:00
Beniamino Galvani
6c1e04fc61 helpers: move helper programs to the same directory
Create a new 'nm-helpers' directory for all the helper programs, to
avoid having too many subdirs in the src directory.
2025-12-12 12:38:48 +01:00
Beniamino Galvani
2739850b78 libnm-core, core: add permission helpers
Add utility functions to get the number of users and the first user
from the connection.permissions property of a connection.
2025-12-12 12:38:48 +01:00
Íñigo Huguet
d8f143f601 spec: enable polkit_noauth_group for Fedora <= 43 and RHEL <= 10
In Fedora 44 and RHEL 11, admin users will need to type their password
even on local consoles.
2025-12-12 12:38:48 +01:00
Íñigo Huguet
39143f8bdd polkit: add build option to allow admin users not to type their password
Add a build option to allow installing a Polkit rule that will grant
permissions for admin users without asking for their password if they're
in a local console.

This shouldn't be encouraged, though. It's common practice that admin
users has to introduce their password to make system-wide changes. The
standard polkit policy, without this rule, is auth_admin_keep. This
policy will ask for the password once and won't ask for it again for
~5 minutes, so it is not too unconvenient.

Different distros use different group names for users with admin rights,
typically 'sudo' or 'wheel'. The build option allows to define the
desired group, or to leave it empty to not install the rule.

However, until the previous commit it was allowed that local users (even
non-admin) could do system-wide changes without introducing a password.
This option allows to maintain the same behavior for admin users,
keeping backwards compatibility so we avoid breaking existing scripts,
for example. We cannot achieve the same for non-admin users because
allowing them to create system-wide connection causes security
vulnerabilities that cannot be fixed in any other way.
2025-12-12 12:38:48 +01:00
Íñigo Huguet
0b75d905e5 polkit: remove the modify_system build option
This build option allowed non-admin users to create system-wide
connections. Generally, this is not a good idea as system-wide changes
should be done by administrators.

However, the main reason for the change is that this can be used to
bypass filesystem permissions, among possibly other attacks. As the
daemon runs as root, a user can create a system-wide connection that
uses a certificate from a different user to authenticate in a WiFi
network protected with 802.1X or a VPN, because as root user the daemon
can access to the file.

This patch does not completely fix the issue, as users can still create
private connections specifying a path to another user's connection. This
will be addressed in other patch. However, this patch is needed too,
because in system-wide connections we don't store which user created the
connection, so there woudn't be any way to check his/her permissions.

This is part of the fix for CVE-2025-9615

See: https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1809
2025-12-12 12:38:48 +01:00
Íñigo Huguet
13bfa44ceb nm-version: set API_VERSION with MICRO+1 (temporary)
In the past, stable branches used odd micro numbers as development micro
version. Because of that, NM_API_VERSION was defined with MICRO+1 so we
don't get warnings during development.

As we stopped using odd micro=devel it is wrong to set MICRO+1 on odd
releases. Final users of 1.52.3 has NM_API_VERSION 1.52.4.

However, during development we need to have MICRO+1. For example, if we
are working on top of 1.52.3 towards the next 1.52.4, we define new
symbols with NM_AVAILABLE_IN_1_52_4. Because of that, we get compilation
failures until we finally bump to 1.52.4, just before the release. The
CI remains red until then, potentially missing many bugs.

For now, just set MICRO+1 all the time. It is wrong, but it was wrong
half of the time anyway, and at least we'll have a green CI until we
implement a definitive solution.
2025-12-12 12:17:58 +01:00