]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/tuntap: deny non-system users/groups from owning Tun/Tap interfaces 37294/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 29 Apr 2025 14:16:02 +0000 (23:16 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 30 Apr 2025 11:31:00 +0000 (20:31 +0900)
This is analogous to #36123, but for Tun/Tap interfaces created by
systemd-networkd.

If a regular user account want to control a Tun/Tap interface, then
assign the interface to a system group, e.g., vpn, and add the user
to the group.

Closes #37279.

NEWS
man/systemd.netdev.xml
src/network/netdev/tuntap.c

diff --git a/NEWS b/NEWS
index 8f6f77c70d0fa0755c21b662e756187e9e5e769b..cc640eaa3d680e122ed700ac7735ae7e012eda75 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -46,6 +46,9 @@ CHANGES WITH 258 in spe:
           owned by a non-system user/group. It is recommended to check udev
           rules files with 'udevadm verify' and/or 'udevadm test' commands if
           the specified user/group in OWNER=/GROUP= are valid.
+          Similarly, systemd-networkd refuses User=/Group= settings with a
+          non-system user/group specified in .netdev files for Tun/Tap
+          interfaces.
 
         * systemd-cryptenroll, systemd-repart and systemd-creds no longer
           default to locking TPM2 enrollments to the current, literal value of
index 9ea59a7763344f91921051a5bdd1780fa6d48381..3bfaf7c21570f81802520dca49a702e1dffa99ae 100644 (file)
@@ -1970,16 +1970,16 @@ Ports=eth2</programlisting>
       </varlistentry>
       <varlistentry>
         <term><varname>User=</varname></term>
-        <listitem><para>User to grant access to the
-        <filename>/dev/net/tun</filename> device.</para>
+        <listitem><para>User to grant access to the <filename>/dev/net/tun</filename> device. The specified
+        user must be a system user.</para>
 
         <xi:include href="version-info.xml" xpointer="v215"/>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>Group=</varname></term>
-        <listitem><para>Group to grant access to the
-        <filename>/dev/net/tun</filename> device.</para>
+        <listitem><para>Group to grant access to the <filename>/dev/net/tun</filename> device. The specified
+        group must be a system group.</para>
 
         <xi:include href="version-info.xml" xpointer="v215"/>
         </listitem>
index c07c71b8a0b161a6afb08b9447e3e9bd48d7652d..48bc0079706add57a3867de97e0d3adfd2d9622d 100644 (file)
@@ -10,6 +10,7 @@
 #include <sys/types.h>
 
 #include "alloc-util.h"
+#include "bitfield.h"
 #include "daemon-util.h"
 #include "fd-util.h"
 #include "networkd-link.h"
@@ -228,9 +229,14 @@ static int tuntap_verify(NetDev *netdev, const char *filename) {
 
         if (t->user_name) {
                 _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
+                UserDBMatch match = USERDB_MATCH_NULL;
 
-                r = userdb_by_name(t->user_name, /* match = */ NULL, USERDB_PARSE_NUMERIC, &ur);
-                if (r < 0)
+                match.disposition_mask = INDEX_TO_MASK(uint64_t, USER_SYSTEM);
+
+                r = userdb_by_name(t->user_name, &match, USERDB_PARSE_NUMERIC, &ur);
+                if (r == -ENOEXEC)
+                        log_netdev_warning_errno(netdev, r, "User %s is not a system user, ignoring.", t->user_name);
+                else if (r < 0)
                         log_netdev_warning_errno(netdev, r, "Cannot resolve user name %s, ignoring: %m", t->user_name);
                 else
                         t->uid = ur->uid;
@@ -238,9 +244,14 @@ static int tuntap_verify(NetDev *netdev, const char *filename) {
 
         if (t->group_name) {
                 _cleanup_(group_record_unrefp) GroupRecord *gr = NULL;
+                UserDBMatch match = USERDB_MATCH_NULL;
+
+                match.disposition_mask = INDEX_TO_MASK(uint64_t, USER_SYSTEM);
 
-                r = groupdb_by_name(t->group_name, /* match = */ NULL, USERDB_PARSE_NUMERIC, &gr);
-                if (r < 0)
+                r = groupdb_by_name(t->group_name, &match, USERDB_PARSE_NUMERIC, &gr);
+                if (r == -ENOEXEC)
+                        log_netdev_warning_errno(netdev, r, "Group %s is not a system group, ignoring.", t->group_name);
+                else if (r < 0)
                         log_netdev_warning_errno(netdev, r, "Cannot resolve group name %s, ignoring: %m", t->group_name);
                 else
                         t->gid = gr->gid;