diff --git a/NEWS b/NEWS
index 8f6f77c70d..cc640eaa3d 100644
--- 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
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index 9ea59a7763..3bfaf7c215 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -1970,16 +1970,16 @@ Ports=eth2
User=
- User to grant access to the
- /dev/net/tun device.
+ User to grant access to the /dev/net/tun device. The specified
+ user must be a system user.
Group=
- Group to grant access to the
- /dev/net/tun device.
+ Group to grant access to the /dev/net/tun device. The specified
+ group must be a system group.
diff --git a/src/network/netdev/tuntap.c b/src/network/netdev/tuntap.c
index 2d96682ca5..48bc007970 100644
--- a/src/network/netdev/tuntap.c
+++ b/src/network/netdev/tuntap.c
@@ -10,13 +10,14 @@
#include
#include "alloc-util.h"
+#include "bitfield.h"
#include "daemon-util.h"
#include "fd-util.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "socket-util.h"
#include "tuntap.h"
-#include "user-util.h"
+#include "userdb.h"
#define TUN_DEV "/dev/net/tun"
@@ -174,31 +175,14 @@ static int netdev_create_tuntap(NetDev *netdev) {
return log_netdev_error_errno(netdev, errno, "TUNSETQUEUE failed: %m");
}
- if (t->user_name) {
- const char *user = t->user_name;
- uid_t uid;
-
- r = get_user_creds(&user, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
- if (r < 0)
- return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
-
- if (ioctl(fd, TUNSETOWNER, uid) < 0)
+ if (t->uid != 0)
+ if (ioctl(fd, TUNSETOWNER, t->uid) < 0)
return log_netdev_error_errno(netdev, errno, "TUNSETOWNER failed: %m");
- }
- if (t->group_name) {
- const char *group = t->group_name;
- gid_t gid;
-
- r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
- if (r < 0)
- return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
-
- if (ioctl(fd, TUNSETGROUP, gid) < 0)
+ if (t->gid != 0)
+ if (ioctl(fd, TUNSETGROUP, t->gid) < 0)
return log_netdev_error_errno(netdev, errno, "TUNSETGROUP failed: %m");
- }
-
if (ioctl(fd, TUNSETPERSIST, 1) < 0)
return log_netdev_error_errno(netdev, errno, "TUNSETPERSIST failed: %m");
@@ -226,6 +210,9 @@ static void tuntap_done(NetDev *netdev) {
}
static int tuntap_verify(NetDev *netdev, const char *filename) {
+ TunTap *t = TUNTAP(netdev);
+ int r;
+
assert(netdev);
if (netdev->mtu != 0)
@@ -240,6 +227,36 @@ static int tuntap_verify(NetDev *netdev, const char *filename) {
"Please set it in the corresponding .network file.",
netdev_kind_to_string(netdev->kind), filename);
+ if (t->user_name) {
+ _cleanup_(user_record_unrefp) UserRecord *ur = NULL;
+ UserDBMatch match = USERDB_MATCH_NULL;
+
+ 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;
+ }
+
+ 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, 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;
+ }
+
return 0;
}
diff --git a/src/network/netdev/tuntap.h b/src/network/netdev/tuntap.h
index e2de8eb6bb..f345548f95 100644
--- a/src/network/netdev/tuntap.h
+++ b/src/network/netdev/tuntap.h
@@ -1,20 +1,21 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-typedef struct TunTap TunTap;
-
#include "netdev.h"
+#include "user-util.h"
-struct TunTap {
+typedef struct TunTap {
NetDev meta;
char *user_name;
+ uid_t uid;
char *group_name;
+ gid_t gid;
bool multi_queue;
bool packet_info;
bool vnet_hdr;
bool keep_fd;
-};
+} TunTap;
DEFINE_NETDEV_CAST(TUN, TunTap);
DEFINE_NETDEV_CAST(TAP, TunTap);