network/tuntap: verify User=/Group= earlier and refuse non-system users/groups (#37294)
Similar to #36123. Closes #37279.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
+39
-22
@@ -10,13 +10,14 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user