#include <sys/mount.h>
#include <unistd.h>
+#include "dlfcn-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
int r;
+ /* Block dlopen() now, to avoid us inadvertently loading shared library from another namespace */
+ block_dlopen();
+
if (userns_fd >= 0) {
/* Can't setns to your own userns, since then you could escalate from non-root to root in
* your own namespace, so check if namespaces are equal before attempting to enter. */
* foreign environment. Note that this has no effect on NSS! (i.e. it only has effect on uses of our
* dlopen_safe(), which we use comprehensively in our codebase, but glibc NSS doesn't bother, of
* course.) */
- block_dlopen();
+ if (!FLAGS_SET(flags, FORK_ALLOW_DLOPEN))
+ block_dlopen();
if (flags & (FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT|FORK_DEATHSIG_SIGKILL))
if (prctl(PR_SET_PDEATHSIG, fork_flags_to_signal(flags)) < 0) {
/* This is much like safe_fork(), but forks twice, and joins the specified namespaces in the middle
* process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that
* /proc/self/fd works correctly. */
+ assert(!FLAGS_SET(flags, FORK_ALLOW_DLOPEN)); /* never allow loading shared library from another ns */
r = safe_fork_full(outer_name,
NULL,
FORK_NEW_NETNS = 1 << 20, /* Run child in its own network namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
FORK_NEW_PIDNS = 1 << 21, /* Run child in its own PID namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
FORK_FREEZE = 1 << 22, /* Don't return in child, just call freeze() instead */
+ FORK_ALLOW_DLOPEN = 1 << 23, /* Do not block dlopen() in child */
- _FORK_PID_ONLY = 1 << 23, /* Don't open a pidfd referencing the child process */
+ _FORK_PID_ONLY = 1 << 24, /* Don't open a pidfd referencing the child process */
} ForkFlags;
int pidref_safe_fork_full(