Merge pull request #30956 from yuwata/nspawn-network-pass-wifi
nspawn: support passing wireless interface to container
This commit is contained in:
+77
-39
@@ -33,71 +33,78 @@ const struct namespace_info namespace_info[] = {
|
||||
|
||||
#define pid_namespace_path(pid, type) procfs_file_alloca(pid, namespace_info[type].proc_path)
|
||||
|
||||
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
|
||||
_cleanup_close_ int pidnsfd = -EBADF, mntnsfd = -EBADF, netnsfd = -EBADF, usernsfd = -EBADF;
|
||||
int rfd = -EBADF;
|
||||
int namespace_open(
|
||||
pid_t pid,
|
||||
int *ret_pidns_fd,
|
||||
int *ret_mntns_fd,
|
||||
int *ret_netns_fd,
|
||||
int *ret_userns_fd,
|
||||
int *ret_root_fd) {
|
||||
|
||||
_cleanup_close_ int pidns_fd = -EBADF, mntns_fd = -EBADF, netns_fd = -EBADF,
|
||||
userns_fd = -EBADF, root_fd = -EBADF;
|
||||
|
||||
assert(pid >= 0);
|
||||
|
||||
if (mntns_fd) {
|
||||
const char *mntns;
|
||||
|
||||
mntns = pid_namespace_path(pid, NAMESPACE_MOUNT);
|
||||
mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (mntnsfd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (pidns_fd) {
|
||||
if (ret_pidns_fd) {
|
||||
const char *pidns;
|
||||
|
||||
pidns = pid_namespace_path(pid, NAMESPACE_PID);
|
||||
pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (pidnsfd < 0)
|
||||
pidns_fd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (pidns_fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (netns_fd) {
|
||||
if (ret_mntns_fd) {
|
||||
const char *mntns;
|
||||
|
||||
mntns = pid_namespace_path(pid, NAMESPACE_MOUNT);
|
||||
mntns_fd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (mntns_fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (ret_netns_fd) {
|
||||
const char *netns;
|
||||
|
||||
netns = pid_namespace_path(pid, NAMESPACE_NET);
|
||||
netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (netnsfd < 0)
|
||||
netns_fd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (netns_fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (userns_fd) {
|
||||
if (ret_userns_fd) {
|
||||
const char *userns;
|
||||
|
||||
userns = pid_namespace_path(pid, NAMESPACE_USER);
|
||||
usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (usernsfd < 0 && errno != ENOENT)
|
||||
userns_fd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (userns_fd < 0 && errno != ENOENT)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (root_fd) {
|
||||
if (ret_root_fd) {
|
||||
const char *root;
|
||||
|
||||
root = procfs_file_alloca(pid, "root");
|
||||
rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
|
||||
if (rfd < 0)
|
||||
root_fd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
|
||||
if (root_fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (pidns_fd)
|
||||
*pidns_fd = TAKE_FD(pidnsfd);
|
||||
if (ret_pidns_fd)
|
||||
*ret_pidns_fd = TAKE_FD(pidns_fd);
|
||||
|
||||
if (mntns_fd)
|
||||
*mntns_fd = TAKE_FD(mntnsfd);
|
||||
if (ret_mntns_fd)
|
||||
*ret_mntns_fd = TAKE_FD(mntns_fd);
|
||||
|
||||
if (netns_fd)
|
||||
*netns_fd = TAKE_FD(netnsfd);
|
||||
if (ret_netns_fd)
|
||||
*ret_netns_fd = TAKE_FD(netns_fd);
|
||||
|
||||
if (userns_fd)
|
||||
*userns_fd = TAKE_FD(usernsfd);
|
||||
if (ret_userns_fd)
|
||||
*ret_userns_fd = TAKE_FD(userns_fd);
|
||||
|
||||
if (root_fd)
|
||||
*root_fd = TAKE_FD(rfd);
|
||||
if (ret_root_fd)
|
||||
*ret_root_fd = TAKE_FD(root_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -221,7 +228,7 @@ int userns_acquire(const char *uid_map, const char *gid_map) {
|
||||
|
||||
r = safe_fork("(sd-mkuserns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL|FORK_NEW_USERNS, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_debug_errno(r, "Failed to fork process (sd-mkuserns): %m");
|
||||
if (r == 0)
|
||||
/* Child. We do nothing here, just freeze until somebody kills us. */
|
||||
freeze();
|
||||
@@ -229,19 +236,50 @@ int userns_acquire(const char *uid_map, const char *gid_map) {
|
||||
xsprintf(path, "/proc/" PID_FMT "/uid_map", pid);
|
||||
r = write_string_file(path, uid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write UID map: %m");
|
||||
return log_debug_errno(r, "Failed to write UID map: %m");
|
||||
|
||||
xsprintf(path, "/proc/" PID_FMT "/gid_map", pid);
|
||||
r = write_string_file(path, gid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write GID map: %m");
|
||||
return log_debug_errno(r, "Failed to write GID map: %m");
|
||||
|
||||
r = namespace_open(pid, NULL, NULL, NULL, &userns_fd, NULL);
|
||||
r = namespace_open(pid,
|
||||
/* ret_pidns_fd = */ NULL,
|
||||
/* ret_mntns_fd = */ NULL,
|
||||
/* ret_netns_fd = */ NULL,
|
||||
&userns_fd,
|
||||
/* ret_root_fd = */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open userns fd: %m");
|
||||
return log_debug_errno(r, "Failed to open userns fd: %m");
|
||||
|
||||
return TAKE_FD(userns_fd);
|
||||
}
|
||||
|
||||
int netns_acquire(void) {
|
||||
_cleanup_(sigkill_waitp) pid_t pid = 0;
|
||||
_cleanup_close_ int netns_fd = -EBADF;
|
||||
int r;
|
||||
|
||||
/* Forks off a process in a new network namespace, acquires a network namespace fd, and then kills
|
||||
* the process again. This way we have a netns fd that is not bound to any process. */
|
||||
|
||||
r = safe_fork("(sd-mknetns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL|FORK_NEW_NETNS, &pid);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to fork process (sd-mknetns): %m");
|
||||
if (r == 0)
|
||||
/* Child. We do nothing here, just freeze until somebody kills us. */
|
||||
freeze();
|
||||
|
||||
r = namespace_open(pid,
|
||||
/* ret_pidns_fd = */ NULL,
|
||||
/* ret_mntns_fd = */ NULL,
|
||||
&netns_fd,
|
||||
/* ret_userns_fd = */ NULL,
|
||||
/* ret_root_fd = */ NULL);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to open netns fd: %m");
|
||||
|
||||
return TAKE_FD(netns_fd);
|
||||
}
|
||||
|
||||
int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type) {
|
||||
|
||||
@@ -22,7 +22,13 @@ extern const struct namespace_info {
|
||||
unsigned int clone_flag;
|
||||
} namespace_info[_NAMESPACE_TYPE_MAX + 1];
|
||||
|
||||
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
|
||||
int namespace_open(
|
||||
pid_t pid,
|
||||
int *ret_pidns_fd,
|
||||
int *ret_mntns_fd,
|
||||
int *ret_netns_fd,
|
||||
int *ret_userns_fd,
|
||||
int *ret_root_fd);
|
||||
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
|
||||
|
||||
int fd_is_ns(int fd, unsigned long nsflag);
|
||||
@@ -45,4 +51,5 @@ static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
|
||||
}
|
||||
|
||||
int userns_acquire(const char *uid_map, const char *gid_map);
|
||||
int netns_acquire(void);
|
||||
int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type);
|
||||
|
||||
@@ -1541,10 +1541,11 @@ int safe_fork_full(
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & (FORK_NEW_MOUNTNS|FORK_NEW_USERNS)) != 0)
|
||||
if ((flags & (FORK_NEW_MOUNTNS|FORK_NEW_USERNS|FORK_NEW_NETNS)) != 0)
|
||||
pid = raw_clone(SIGCHLD|
|
||||
(FLAGS_SET(flags, FORK_NEW_MOUNTNS) ? CLONE_NEWNS : 0) |
|
||||
(FLAGS_SET(flags, FORK_NEW_USERNS) ? CLONE_NEWUSER : 0));
|
||||
(FLAGS_SET(flags, FORK_NEW_USERNS) ? CLONE_NEWUSER : 0) |
|
||||
(FLAGS_SET(flags, FORK_NEW_NETNS) ? CLONE_NEWNET : 0));
|
||||
else
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
|
||||
@@ -154,11 +154,11 @@ int must_be_root(void);
|
||||
|
||||
pid_t clone_with_nested_stack(int (*fn)(void *), int flags, void *userdata);
|
||||
|
||||
/* 💣 Note that FORK_NEW_USERNS + FORK_NEW_MOUNTNS should not be called in threaded programs, because they
|
||||
* cause us to use raw_clone() which does not synchronize the glibc malloc() locks, and thus will cause
|
||||
* deadlocks if the parent uses threads and the child does memory allocations. Hence: if the parent is
|
||||
* threaded these flags may not be used. These flags cannot be used if the parent uses threads or the child
|
||||
* uses malloc(). 💣 */
|
||||
/* 💣 Note that FORK_NEW_USERNS, FORK_NEW_MOUNTNS, or FORK_NEW_NETNS should not be called in threaded
|
||||
* programs, because they cause us to use raw_clone() which does not synchronize the glibc malloc() locks,
|
||||
* and thus will cause deadlocks if the parent uses threads and the child does memory allocations. Hence: if
|
||||
* the parent is threaded these flags may not be used. These flags cannot be used if the parent uses threads
|
||||
* or the child uses malloc(). 💣 */
|
||||
typedef enum ForkFlags {
|
||||
FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */
|
||||
FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */
|
||||
@@ -179,6 +179,7 @@ typedef enum ForkFlags {
|
||||
FORK_CLOEXEC_OFF = 1 << 16, /* In the child: turn off O_CLOEXEC on all fds in except_fds[] */
|
||||
FORK_KEEP_NOTIFY_SOCKET = 1 << 17, /* Unless this specified, $NOTIFY_SOCKET will be unset. */
|
||||
FORK_DETACH = 1 << 18, /* Double fork if needed to ensure PID1/subreaper is parent */
|
||||
FORK_NEW_NETNS = 1 << 19, /* Run child in its own network namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
|
||||
} ForkFlags;
|
||||
|
||||
int safe_fork_full(
|
||||
|
||||
@@ -1211,7 +1211,7 @@ int openpt_allocate_in_namespace(pid_t pid, int flags, char **ret_slave) {
|
||||
|
||||
assert(pid > 0);
|
||||
|
||||
r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
|
||||
r = namespace_open(pid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, &usernsfd, &rootfd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1262,7 +1262,7 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
|
||||
pid_t child;
|
||||
int r;
|
||||
|
||||
r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
|
||||
r = namespace_open(pid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, &usernsfd, &rootfd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ int bus_container_connect_socket(sd_bus *b) {
|
||||
log_debug("sd-bus: connecting bus%s%s to namespace of PID "PID_FMT"...",
|
||||
b->description ? " " : "", strempty(b->description), b->nspid);
|
||||
|
||||
r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
|
||||
r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, &usernsfd, &rootfd);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to open namespace of PID "PID_FMT": %m", b->nspid);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ int device_get_property_bool(sd_device *device, const char *key);
|
||||
int device_get_property_int(sd_device *device, const char *key, int *ret);
|
||||
int device_get_sysattr_int(sd_device *device, const char *sysattr, int *ret_value);
|
||||
int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned *ret_value);
|
||||
int device_get_sysattr_u32(sd_device *device, const char *sysattr, uint32_t *ret_value);
|
||||
int device_get_sysattr_bool(sd_device *device, const char *sysattr);
|
||||
int device_get_device_id(sd_device *device, const char **ret);
|
||||
int device_get_devlink_priority(sd_device *device, int *ret);
|
||||
|
||||
@@ -2423,6 +2423,25 @@ int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned
|
||||
return v > 0;
|
||||
}
|
||||
|
||||
int device_get_sysattr_u32(sd_device *device, const char *sysattr, uint32_t *ret_value) {
|
||||
const char *value;
|
||||
int r;
|
||||
|
||||
r = sd_device_get_sysattr_value(device, sysattr, &value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
uint32_t v;
|
||||
r = safe_atou32(value, &v);
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(device, r, "Failed to parse '%s' attribute: %m", sysattr);
|
||||
|
||||
if (ret_value)
|
||||
*ret_value = v;
|
||||
/* We return "true" if the value is positive. */
|
||||
return v > 0;
|
||||
}
|
||||
|
||||
int device_get_sysattr_bool(sd_device *device, const char *sysattr) {
|
||||
const char *value;
|
||||
int r;
|
||||
|
||||
@@ -199,6 +199,7 @@ static const NLAPolicy genl_nl80211_policies[] = {
|
||||
[NL80211_ATTR_SSID] = BUILD_POLICY_WITH_SIZE(BINARY, IEEE80211_MAX_SSID_LEN),
|
||||
[NL80211_ATTR_STATUS_CODE] = BUILD_POLICY(U16),
|
||||
[NL80211_ATTR_4ADDR] = BUILD_POLICY(U8),
|
||||
[NL80211_ATTR_NETNS_FD] = BUILD_POLICY(U32),
|
||||
};
|
||||
|
||||
/***************** genl wireguard type systems *****************/
|
||||
|
||||
@@ -20,6 +20,13 @@ static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
|
||||
assert(name);
|
||||
|
||||
/* Assign the requested name. */
|
||||
|
||||
if (!*rtnl) {
|
||||
r = sd_netlink_open(rtnl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -31,6 +38,37 @@ static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
|
||||
return sd_netlink_call(*rtnl, message, 0, NULL);
|
||||
}
|
||||
|
||||
int rtnl_rename_link(sd_netlink **rtnl, const char *orig_name, const char *new_name) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
|
||||
int r, ifindex;
|
||||
|
||||
assert(orig_name);
|
||||
assert(new_name);
|
||||
|
||||
/* This does not check alternative names. Callers must check the requested name is not used as an
|
||||
* alternative name. */
|
||||
|
||||
if (streq(orig_name, new_name))
|
||||
return 0;
|
||||
|
||||
if (!ifname_valid(new_name))
|
||||
return -EINVAL;
|
||||
|
||||
if (!rtnl)
|
||||
rtnl = &our_rtnl;
|
||||
if (!*rtnl) {
|
||||
r = sd_netlink_open(rtnl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ifindex = rtnl_resolve_ifname(rtnl, orig_name);
|
||||
if (ifindex < 0)
|
||||
return ifindex;
|
||||
|
||||
return set_link_name(rtnl, ifindex, new_name);
|
||||
}
|
||||
|
||||
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const *alternative_names) {
|
||||
_cleanup_strv_free_ char **original_altnames = NULL, **new_altnames = NULL;
|
||||
bool altname_deleted = false;
|
||||
|
||||
@@ -31,6 +31,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free);
|
||||
|
||||
int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret);
|
||||
|
||||
int rtnl_rename_link(sd_netlink **rtnl, const char *orig_name, const char *new_name);
|
||||
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const* alternative_names);
|
||||
static inline int rtnl_append_link_alternative_names(sd_netlink **rtnl, int ifindex, char* const *alternative_names) {
|
||||
return rtnl_set_link_name(rtnl, ifindex, NULL, alternative_names);
|
||||
|
||||
@@ -681,6 +681,19 @@ TEST(rtnl_set_link_name) {
|
||||
_cleanup_free_ char *resolved = NULL;
|
||||
assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-additional-name", &resolved) == ifindex);
|
||||
assert_se(streq_ptr(resolved, "test-shortname"));
|
||||
resolved = mfree(resolved);
|
||||
|
||||
assert_se(rtnl_rename_link(&rtnl, "test-shortname", "test-shortname") >= 0);
|
||||
assert_se(rtnl_rename_link(&rtnl, "test-shortname", "test-shortname2") >= 0);
|
||||
assert_se(rtnl_rename_link(NULL, "test-shortname2", "test-shortname3") >= 0);
|
||||
|
||||
assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-additional-name", &resolved) == ifindex);
|
||||
assert_se(streq_ptr(resolved, "test-shortname3"));
|
||||
resolved = mfree(resolved);
|
||||
|
||||
assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-shortname3", &resolved) == ifindex);
|
||||
assert_se(streq_ptr(resolved, "test-shortname3"));
|
||||
resolved = mfree(resolved);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
||||
@@ -232,7 +232,12 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
|
||||
if (streq(us, them))
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
|
||||
|
||||
r = namespace_open(m->leader.pid, NULL, NULL, &netns_fd, NULL, NULL);
|
||||
r = namespace_open(m->leader.pid,
|
||||
/* ret_pidns_fd = */ NULL,
|
||||
/* ret_mntns_fd = */ NULL,
|
||||
&netns_fd,
|
||||
/* ret_userns_fd = */ NULL,
|
||||
/* ret_root_fd = */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -366,7 +371,12 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
pid_t child;
|
||||
|
||||
r = namespace_open(m->leader.pid, &pidns_fd, &mntns_fd, NULL, NULL, &root_fd);
|
||||
r = namespace_open(m->leader.pid,
|
||||
&pidns_fd,
|
||||
&mntns_fd,
|
||||
/* ret_netns_fd = */ NULL,
|
||||
/* ret_userns_fd = */ NULL,
|
||||
&root_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1069,7 +1079,12 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda
|
||||
_cleanup_close_pair_ int pair[2] = EBADF_PAIR;
|
||||
pid_t child;
|
||||
|
||||
r = namespace_open(m->leader.pid, NULL, &mntns_fd, NULL, NULL, &root_fd);
|
||||
r = namespace_open(m->leader.pid,
|
||||
/* ret_pidns_fd = */ NULL,
|
||||
&mntns_fd,
|
||||
/* ret_netns_fd = */ NULL,
|
||||
/* ret_userns_fd = */ NULL,
|
||||
&root_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -1388,17 +1388,30 @@ int wipe_fully_visible_fs(int mntns_fd) {
|
||||
_cleanup_close_ int orig_mntns_fd = -EBADF;
|
||||
int r, rr;
|
||||
|
||||
r = namespace_open(0, NULL, &orig_mntns_fd, NULL, NULL, NULL);
|
||||
r = namespace_open(0,
|
||||
/* ret_pidns_fd = */ NULL,
|
||||
&orig_mntns_fd,
|
||||
/* ret_netns_fd = */ NULL,
|
||||
/* ret_userns_fd = */ NULL,
|
||||
/* ret_root_fd = */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to pin originating mount namespace: %m");
|
||||
|
||||
r = namespace_enter(-EBADF, mntns_fd, -EBADF, -EBADF, -EBADF);
|
||||
r = namespace_enter(/* pidns_fd = */ -EBADF,
|
||||
mntns_fd,
|
||||
/* netns_fd = */ -EBADF,
|
||||
/* userns_fd = */ -EBADF,
|
||||
/* root_fd = */ -EBADF);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enter mount namespace: %m");
|
||||
|
||||
rr = do_wipe_fully_visible_fs();
|
||||
|
||||
r = namespace_enter(-EBADF, orig_mntns_fd, -EBADF, -EBADF, -EBADF);
|
||||
r = namespace_enter(/* pidns_fd = */ -EBADF,
|
||||
orig_mntns_fd,
|
||||
/* netns_fd = */ -EBADF,
|
||||
/* userns_fd = */ -EBADF,
|
||||
/* root_fd = */ -EBADF);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enter original mount namespace: %m");
|
||||
|
||||
|
||||
+302
-29
@@ -2,22 +2,31 @@
|
||||
|
||||
#include <net/if.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/nl80211.h>
|
||||
#include <linux/veth.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-id128.h"
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "lock-util.h"
|
||||
#include "missing_network.h"
|
||||
#include "mkdir.h"
|
||||
#include "mount-util.h"
|
||||
#include "namespace-util.h"
|
||||
#include "netif-naming-scheme.h"
|
||||
#include "netlink-util.h"
|
||||
#include "nspawn-network.h"
|
||||
#include "parse-util.h"
|
||||
#include "process-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "socket-netlink.h"
|
||||
#include "socket-util.h"
|
||||
@@ -503,42 +512,306 @@ int test_network_interfaces_initialized(char **iface_pairs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int move_network_interfaces(int netns_fd, char **iface_pairs) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
static int netns_child_begin(int netns_fd, int *ret_original_netns_fd) {
|
||||
_cleanup_close_ int original_netns_fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(netns_fd >= 0);
|
||||
|
||||
if (ret_original_netns_fd) {
|
||||
r = namespace_open(0,
|
||||
/* ret_pidns_fd = */ NULL,
|
||||
/* ret_mntns_fd = */ NULL,
|
||||
&original_netns_fd,
|
||||
/* ret_userns_fd = */ NULL,
|
||||
/* ret_root_fd = */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open original network namespace: %m");
|
||||
}
|
||||
|
||||
r = namespace_enter(/* pidns_fd = */ -EBADF,
|
||||
/* mntns_fd = */ -EBADF,
|
||||
netns_fd,
|
||||
/* userns_fd = */ -EBADF,
|
||||
/* root_fd = */ -EBADF);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enter child network namespace: %m");
|
||||
|
||||
r = umount_recursive("/sys/", /* flags = */ 0);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to unmount directories below /sys/, ignoring: %m");
|
||||
|
||||
(void) mkdir_p("/sys/", 0755);
|
||||
|
||||
/* Populate new sysfs instance associated with the client netns, to make sd_device usable. */
|
||||
r = mount_nofollow_verbose(LOG_ERR, "sysfs", "/sys/", "sysfs",
|
||||
MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, /* opts = */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to mount sysfs on /sys/: %m");
|
||||
|
||||
/* udev_avaliable() might be called previously and the result may be cached.
|
||||
* Now, we (re-)mount sysfs. Hence, we need to reset the cache. */
|
||||
reset_cached_udev_availability();
|
||||
|
||||
if (ret_original_netns_fd)
|
||||
*ret_original_netns_fd = TAKE_FD(original_netns_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netns_fork_and_wait(int netns_fd, int *ret_original_netns_fd) {
|
||||
int r;
|
||||
|
||||
assert(netns_fd >= 0);
|
||||
|
||||
r = safe_fork("(sd-netns)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork process (sd-netns): %m");
|
||||
if (r == 0) {
|
||||
if (netns_child_begin(netns_fd, ret_original_netns_fd) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret_original_netns_fd)
|
||||
*ret_original_netns_fd = -EBADF;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int needs_rename(sd_netlink **rtnl, sd_device *dev, const char *name) {
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(dev);
|
||||
assert(name);
|
||||
|
||||
const char *ifname;
|
||||
r = sd_device_get_sysname(dev, &ifname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (streq(name, ifname))
|
||||
return false;
|
||||
|
||||
int ifindex;
|
||||
r = sd_device_get_ifindex(dev, &ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
_cleanup_strv_free_ char **altnames = NULL;
|
||||
r = rtnl_get_link_alternative_names(rtnl, ifindex, &altnames);
|
||||
if (r == -EOPNOTSUPP)
|
||||
return true; /* alternative interface name is not supported, hence the name is not
|
||||
* assigned to the interface. */
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return !strv_contains(altnames, name);
|
||||
}
|
||||
|
||||
static int move_wlan_interface_impl(sd_netlink **genl, int netns_fd, sd_device *dev) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *our_genl = NULL;
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(netns_fd >= 0);
|
||||
assert(dev);
|
||||
|
||||
if (!genl)
|
||||
genl = &our_genl;
|
||||
if (!*genl) {
|
||||
r = sd_genl_socket_open(genl);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to generic netlink: %m");
|
||||
}
|
||||
|
||||
r = sd_genl_message_new(*genl, NL80211_GENL_NAME, NL80211_CMD_SET_WIPHY_NETNS, &m);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to allocate netlink message: %m");
|
||||
|
||||
uint32_t phy_index;
|
||||
r = device_get_sysattr_u32(dev, "phy80211/index", &phy_index);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to get phy index: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(m, NL80211_ATTR_WIPHY, phy_index);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to append phy index to netlink message: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(m, NL80211_ATTR_NETNS_FD, netns_fd);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to append namespace fd to netlink message: %m");
|
||||
|
||||
r = sd_netlink_call(*genl, m, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to move interface to namespace: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int move_wlan_interface_one(
|
||||
sd_netlink **rtnl,
|
||||
sd_netlink **genl,
|
||||
int *temp_netns_fd,
|
||||
int netns_fd,
|
||||
sd_device *dev,
|
||||
const char *name) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(genl);
|
||||
assert(temp_netns_fd);
|
||||
assert(netns_fd >= 0);
|
||||
assert(dev);
|
||||
assert(name);
|
||||
|
||||
r = needs_rename(rtnl, dev, name);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to determine if the interface should be renamed to '%s': %m", name);
|
||||
if (r == 0)
|
||||
return move_wlan_interface_impl(genl, netns_fd, dev);
|
||||
|
||||
/* The command NL80211_CMD_SET_WIPHY_NETNS takes phy instead of network interface, and does not take
|
||||
* an interface name in the passed network namespace. Hence, we need to move the phy and interface to
|
||||
* a temporary network namespace, rename the interface in it, and move them to the requested netns. */
|
||||
|
||||
if (*temp_netns_fd < 0) {
|
||||
r = netns_acquire();
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to acquire new network namespace: %m");
|
||||
*temp_netns_fd = r;
|
||||
}
|
||||
|
||||
r = move_wlan_interface_impl(genl, *temp_netns_fd, dev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
const char *sysname;
|
||||
r = sd_device_get_sysname(dev, &sysname);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to get interface name: %m");
|
||||
|
||||
r = netns_fork_and_wait(*temp_netns_fd, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork process (nspawn-rename-wlan): %m");
|
||||
if (r == 0) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *temp_dev = NULL;
|
||||
|
||||
r = rtnl_rename_link(NULL, sysname, name);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to rename network interface '%s' to '%s': %m", sysname, name);
|
||||
goto finalize;
|
||||
}
|
||||
|
||||
r = sd_device_new_from_ifname(&temp_dev, name);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to acquire device '%s': %m", name);
|
||||
goto finalize;
|
||||
}
|
||||
|
||||
r = move_wlan_interface_impl(NULL, netns_fd, temp_dev);
|
||||
|
||||
finalize:
|
||||
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int move_network_interface_one(sd_netlink **rtnl, int netns_fd, sd_device *dev, const char *name) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(rtnl);
|
||||
assert(netns_fd >= 0);
|
||||
assert(dev);
|
||||
assert(name);
|
||||
|
||||
if (!*rtnl) {
|
||||
r = sd_netlink_open(rtnl);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to rtnetlink: %m");
|
||||
}
|
||||
|
||||
int ifindex;
|
||||
r = sd_device_get_ifindex(dev, &ifindex);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to get ifindex: %m");
|
||||
|
||||
r = sd_rtnl_message_new_link(*rtnl, &m, RTM_SETLINK, ifindex);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to allocate netlink message: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_NET_NS_FD, netns_fd);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to append namespace fd to netlink message: %m");
|
||||
|
||||
r = needs_rename(rtnl, dev, name);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to determine if the interface should be renamed to '%s': %m", name);
|
||||
if (r > 0) {
|
||||
r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to add netlink interface name: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_call(*rtnl, m, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to move interface to namespace: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int move_network_interfaces(int netns_fd, char **iface_pairs) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL, *genl = NULL;
|
||||
_cleanup_close_ int temp_netns_fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(netns_fd >= 0);
|
||||
|
||||
if (strv_isempty(iface_pairs))
|
||||
return 0;
|
||||
|
||||
r = sd_netlink_open(&rtnl);
|
||||
STRV_FOREACH_PAIR(from, to, iface_pairs) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
||||
|
||||
r = sd_device_new_from_ifname(&dev, *from);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Unknown interface name %s: %m", *from);
|
||||
|
||||
if (device_is_devtype(dev, "wlan"))
|
||||
r = move_wlan_interface_one(&rtnl, &genl, &temp_netns_fd, netns_fd, dev, *to);
|
||||
else
|
||||
r = move_network_interface_one(&rtnl, netns_fd, dev, *to);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int move_back_network_interfaces(int child_netns_fd, char **interface_pairs) {
|
||||
_cleanup_close_ int parent_netns_fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(child_netns_fd >= 0);
|
||||
|
||||
if (strv_isempty(interface_pairs))
|
||||
return 0;
|
||||
|
||||
r = netns_fork_and_wait(child_netns_fd, &parent_netns_fd);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to netlink: %m");
|
||||
return r;
|
||||
if (r == 0) {
|
||||
/* Reverse network interfaces pair list so that interfaces get their initial name back.
|
||||
* This is about ensuring interfaces get their old name back when being moved back. */
|
||||
interface_pairs = strv_reverse(interface_pairs);
|
||||
|
||||
STRV_FOREACH_PAIR(i, b, iface_pairs) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int ifi;
|
||||
|
||||
ifi = rtnl_resolve_interface_or_warn(&rtnl, *i);
|
||||
if (ifi < 0)
|
||||
return ifi;
|
||||
|
||||
r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, ifi);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate netlink message: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_NET_NS_FD, netns_fd);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to append namespace fd to netlink message: %m");
|
||||
|
||||
if (!streq(*b, *i)) {
|
||||
r = sd_netlink_message_append_string(m, IFLA_IFNAME, *b);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add netlink interface name: %m");
|
||||
}
|
||||
|
||||
r = sd_netlink_call(rtnl, m, 0, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i);
|
||||
r = move_network_interfaces(parent_netns_fd, interface_pairs);
|
||||
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -19,6 +19,7 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **iface_pairs);
|
||||
int setup_ipvlan(const char *machine_name, pid_t pid, char **iface_pairs);
|
||||
|
||||
int move_network_interfaces(int netns_fd, char **iface_pairs);
|
||||
int move_back_network_interfaces(int child_netns_fd, char **interface_pairs);
|
||||
|
||||
int veth_extra_parse(char ***l, const char *p);
|
||||
|
||||
|
||||
+18
-32
@@ -3781,7 +3781,12 @@ static int outer_child(
|
||||
return r;
|
||||
|
||||
if (arg_userns_mode != USER_NAMESPACE_NO) {
|
||||
r = namespace_open(0, NULL, &mntns_fd, NULL, NULL, NULL);
|
||||
r = namespace_open(0,
|
||||
/* ret_pidns_fd = */ NULL,
|
||||
&mntns_fd,
|
||||
/* ret_netns_fd = */ NULL,
|
||||
/* ret_userns_fd = */ NULL,
|
||||
/* ret_root_fd = */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to pin outer mount namespace: %m");
|
||||
|
||||
@@ -4130,7 +4135,11 @@ static int outer_child(
|
||||
* user if user namespaces are turned on. */
|
||||
|
||||
if (arg_network_namespace_path) {
|
||||
r = namespace_enter(-1, -1, netns_fd, -1, -1);
|
||||
r = namespace_enter(/* pidns_fd = */ -EBADF,
|
||||
/* mntns_fd = */ -EBADF,
|
||||
netns_fd,
|
||||
/* userns_fd = */ -EBADF,
|
||||
/* root_fd = */ -EBADF);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to join network namespace: %m");
|
||||
}
|
||||
@@ -5078,7 +5087,12 @@ static int run_container(
|
||||
if (child_netns_fd < 0) {
|
||||
/* Make sure we have an open file descriptor to the child's network
|
||||
* namespace so it stays alive even if the child exits. */
|
||||
r = namespace_open(*pid, NULL, NULL, &child_netns_fd, NULL, NULL);
|
||||
r = namespace_open(*pid,
|
||||
/* ret_pidns_fd = */ NULL,
|
||||
/* ret_mntns_fd = */ NULL,
|
||||
&child_netns_fd,
|
||||
/* ret_userns_fd = */ NULL,
|
||||
/* ret_root_fd = */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open child network namespace: %m");
|
||||
}
|
||||
@@ -5363,37 +5377,9 @@ static int run_container(
|
||||
fd_kmsg_fifo = safe_close(fd_kmsg_fifo);
|
||||
|
||||
if (arg_private_network) {
|
||||
/* Move network interfaces back to the parent network namespace. We use `safe_fork`
|
||||
* to avoid having to move the parent to the child network namespace. */
|
||||
r = safe_fork(NULL, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
|
||||
r = move_back_network_interfaces(child_netns_fd, arg_network_interfaces);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r == 0) {
|
||||
_cleanup_close_ int parent_netns_fd = -EBADF;
|
||||
|
||||
r = namespace_open(getpid_cached(), NULL, NULL, &parent_netns_fd, NULL, NULL);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to open parent network namespace: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = namespace_enter(-1, -1, child_netns_fd, -1, -1);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to enter child network namespace: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Reverse network interfaces pair list so that interfaces get their initial name back.
|
||||
* This is about ensuring interfaces get their old name back when being moved back. */
|
||||
arg_network_interfaces = strv_reverse(arg_network_interfaces);
|
||||
|
||||
r = move_network_interfaces(parent_netns_fd, arg_network_interfaces);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to move network interfaces back to parent network namespace: %m");
|
||||
|
||||
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
r = wait_for_container(TAKE_PID(*pid), &container_status);
|
||||
|
||||
@@ -1688,7 +1688,7 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, NULL, &rootfd);
|
||||
r = namespace_open(pid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, /* ret_userns_fd = */ NULL, &rootfd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -265,7 +265,12 @@ int machine_id_commit(const char *root) {
|
||||
fd = safe_close(fd);
|
||||
|
||||
/* Store current mount namespace */
|
||||
r = namespace_open(0, NULL, &initial_mntns_fd, NULL, NULL, NULL);
|
||||
r = namespace_open(0,
|
||||
/* ret_pidns_fd = */ NULL,
|
||||
&initial_mntns_fd,
|
||||
/* ret_netns_fd = */ NULL,
|
||||
/* ret_userns_fd = */ NULL,
|
||||
/* ret_root_fd = */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Can't fetch current mount namespace: %m");
|
||||
|
||||
@@ -284,7 +289,11 @@ int machine_id_commit(const char *root) {
|
||||
return log_error_errno(r, "Cannot write %s. This is mandatory to get a persistent machine ID: %m", etc_machine_id);
|
||||
|
||||
/* Return to initial namespace and proceed a lazy tmpfs unmount */
|
||||
r = namespace_enter(-1, initial_mntns_fd, -1, -1, -1);
|
||||
r = namespace_enter(/* pidns_fd = */ -EBADF,
|
||||
initial_mntns_fd,
|
||||
/* netns_fd = */ -EBADF,
|
||||
/* userns_fd = */ -EBADF,
|
||||
/* root_fd = */ -EBADF);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to switch back to initial mount namespace: %m.\nWe'll keep transient %s file until next reboot.", etc_machine_id);
|
||||
|
||||
|
||||
@@ -1100,7 +1100,7 @@ static int mount_in_namespace(
|
||||
if (!pidref_is_set(target))
|
||||
return -ESRCH;
|
||||
|
||||
r = namespace_open(target->pid, &pidns_fd, &mntns_fd, NULL, NULL, &root_fd);
|
||||
r = namespace_open(target->pid, &pidns_fd, &mntns_fd, /* ret_netns_fd = */ NULL, /* ret_userns_fd = */ NULL, &root_fd);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to retrieve FDs of the target process' namespace: %m");
|
||||
|
||||
|
||||
@@ -420,11 +420,11 @@ int netns_get_nsid(int netnsfd, uint32_t *ret) {
|
||||
if (netnsfd < 0) {
|
||||
r = namespace_open(
|
||||
0,
|
||||
/* pidns_fd= */ NULL,
|
||||
/* mntns_fd= */ NULL,
|
||||
/* ret_pidns_fd = */ NULL,
|
||||
/* ret_mntns_fd = */ NULL,
|
||||
&_netns_fd,
|
||||
/* userns_fd= */ NULL,
|
||||
/* root_fd= */ NULL);
|
||||
/* ret_userns_fd = */ NULL,
|
||||
/* ret_root_fd = */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
+10
-5
@@ -14,6 +14,7 @@
|
||||
#include "id128-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "missing_threads.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "signal-util.h"
|
||||
@@ -363,18 +364,22 @@ int udev_queue_is_empty(void) {
|
||||
(errno == ENOENT ? true : -errno) : false;
|
||||
}
|
||||
|
||||
bool udev_available(void) {
|
||||
static int cache = -1;
|
||||
static int cached_udev_availability = -1;
|
||||
|
||||
void reset_cached_udev_availability(void) {
|
||||
cached_udev_availability = -1;
|
||||
}
|
||||
|
||||
bool udev_available(void) {
|
||||
/* The service systemd-udevd is started only when /sys is read write.
|
||||
* See systemd-udevd.service: ConditionPathIsReadWrite=/sys
|
||||
* Also, our container interface (http://systemd.io/CONTAINER_INTERFACE/) states that /sys must
|
||||
* be mounted in read-only mode in containers. */
|
||||
|
||||
if (cache >= 0)
|
||||
return cache;
|
||||
if (cached_udev_availability >= 0)
|
||||
return cached_udev_availability;
|
||||
|
||||
return (cache = (path_is_read_only_fs("/sys/") <= 0));
|
||||
return (cached_udev_availability = (path_is_read_only_fs("/sys/") <= 0));
|
||||
}
|
||||
|
||||
int device_get_vendor_string(sd_device *device, const char **ret) {
|
||||
|
||||
@@ -23,6 +23,7 @@ size_t udev_replace_chars(char *str, const char *allow);
|
||||
|
||||
int udev_queue_is_empty(void);
|
||||
|
||||
void reset_cached_udev_availability(void);
|
||||
bool udev_available(void);
|
||||
|
||||
int device_get_vendor_string(sd_device *device, const char **ret);
|
||||
|
||||
@@ -13,6 +13,10 @@ test_append_files() {
|
||||
local workspace="${1:?}"
|
||||
local container="$workspace/testsuite-13-container-template"
|
||||
|
||||
# For virtual wlan interface.
|
||||
instmods mac80211_hwsim
|
||||
generate_module_dependencies
|
||||
|
||||
# Create a dummy container "template" with a minimal toolset, which we can
|
||||
# then use as a base for our nspawn/machinectl tests
|
||||
initdir="$container" setup_basic_dirs
|
||||
|
||||
@@ -324,7 +324,7 @@ EOF
|
||||
}
|
||||
|
||||
nspawn_settings_cleanup() {
|
||||
for dev in sd-host-only sd-shared{1,2} sd-macvlan{1,2} sd-ipvlan{1,2}; do
|
||||
for dev in sd-host-only sd-shared{1,2,3} sd-macvlan{1,2} sd-ipvlan{1,2}; do
|
||||
ip link del "$dev" || :
|
||||
done
|
||||
|
||||
@@ -332,7 +332,7 @@ nspawn_settings_cleanup() {
|
||||
}
|
||||
|
||||
testcase_nspawn_settings() {
|
||||
local root container dev private_users
|
||||
local root container dev private_users wlan_names='' wlan_checks=''
|
||||
|
||||
mkdir -p /run/systemd/nspawn
|
||||
root="$(mktemp -d /var/lib/machines/testsuite-13.nspawn-settings.XXX)"
|
||||
@@ -341,10 +341,17 @@ testcase_nspawn_settings() {
|
||||
rm -f "/etc/systemd/nspawn/$container.nspawn"
|
||||
mkdir -p "$root/tmp" "$root"/opt/{tmp,inaccessible,also-inaccessible}
|
||||
|
||||
for dev in sd-host-only sd-shared{1,2} sd-macvlan{1,2} sd-macvlanloong sd-ipvlan{1,2} sd-ipvlanlooong; do
|
||||
# add virtual wlan interfaces
|
||||
if modprobe mac80211_hwsim radios=2; then
|
||||
wlan_names='wlan0 wlan1:wl-renamed1'
|
||||
wlan_checks='ip link | grep wlan0\nip link | grep wl-renamed1'
|
||||
fi
|
||||
|
||||
for dev in sd-host-only sd-shared{1,2,3} sd-macvlan{1,2} sd-macvlanloong sd-ipvlan{1,2} sd-ipvlanlooong; do
|
||||
ip link add "$dev" type dummy
|
||||
done
|
||||
udevadm settle
|
||||
ip link property add dev sd-shared3 altname sd-altname3 altname sd-altname-tooooooooooooo-long
|
||||
ip link
|
||||
trap nspawn_settings_cleanup RETURN
|
||||
|
||||
@@ -394,7 +401,7 @@ Private=yes
|
||||
VirtualEthernet=yes
|
||||
VirtualEthernetExtra=my-fancy-veth1
|
||||
VirtualEthernetExtra=fancy-veth2:my-fancy-veth2
|
||||
Interface=sd-shared1 sd-shared2:sd-shared2
|
||||
Interface=sd-shared1 sd-shared2:sd-renamed2 sd-shared3:sd-altname3 ${wlan_names}
|
||||
MACVLAN=sd-macvlan1 sd-macvlan2:my-macvlan2 sd-macvlanloong
|
||||
IPVLAN=sd-ipvlan1 sd-ipvlan2:my-ipvlan2 sd-ipvlanlooong
|
||||
Zone=sd-zone0
|
||||
@@ -437,12 +444,17 @@ ip link | grep host0@
|
||||
ip link | grep my-fancy-veth1@
|
||||
ip link | grep my-fancy-veth2@
|
||||
ip link | grep sd-shared1
|
||||
ip link | grep sd-shared2
|
||||
ip link | grep sd-renamed2
|
||||
ip link | grep sd-shared3
|
||||
ip link | grep sd-altname3
|
||||
ip link | grep sd-altname-tooooooooooooo-long
|
||||
ip link | grep mv-sd-macvlan1@
|
||||
ip link | grep my-macvlan2@
|
||||
ip link | grep iv-sd-ipvlan1@
|
||||
ip link | grep my-ipvlan2@
|
||||
EOF
|
||||
echo -e "$wlan_checks" >>"$root/entrypoint.sh"
|
||||
|
||||
timeout 30 systemd-nspawn --directory="$root"
|
||||
|
||||
# And now for stuff that needs to run separately
|
||||
|
||||
Reference in New Issue
Block a user