Skip to content

Commit

Permalink
Merge pull request containers#9928 from pendulm/fix_rootless_socket_a…
Browse files Browse the repository at this point in the history
…ctivation

Fix rootless socket activation
  • Loading branch information
openshift-merge-robot authored Apr 5, 2021
2 parents 9005f40 + 11917a1 commit 1c8d3d0
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 12 deletions.
58 changes: 46 additions & 12 deletions pkg/rootless/rootless_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ static int open_files_max_fd;
static fd_set *open_files_set;
static uid_t rootless_uid_init;
static gid_t rootless_gid_init;
static bool do_socket_activation = false;
static char *saved_systemd_listen_fds;
static char *saved_systemd_listen_pid;
static char *saved_systemd_listen_fdnames;

static int
syscall_setresuid (uid_t ruid, uid_t euid, uid_t suid)
Expand Down Expand Up @@ -242,6 +246,10 @@ static void __attribute__((constructor)) init()
{
const char *xdg_runtime_dir;
const char *pause;
const char *listen_pid;
const char *listen_fds;
const char *listen_fdnames;

DIR *d;

pause = getenv ("_PODMAN_PAUSE");
Expand Down Expand Up @@ -293,6 +301,26 @@ static void __attribute__((constructor)) init()
closedir (d);
}

listen_pid = getenv("LISTEN_PID");
listen_fds = getenv("LISTEN_FDS");
listen_fdnames = getenv("LISTEN_FDNAMES");

if (listen_pid != NULL && listen_fds != NULL && strtol(listen_pid, NULL, 10) == getpid())
{
// save systemd socket environment for rootless child
do_socket_activation = true;
saved_systemd_listen_pid = strdup(listen_pid);
saved_systemd_listen_fds = strdup(listen_fds);
saved_systemd_listen_fdnames = strdup(listen_fdnames);
if (saved_systemd_listen_pid == NULL
|| saved_systemd_listen_fds == NULL
|| saved_systemd_listen_fdnames == NULL)
{
fprintf (stderr, "save socket listen environments error: %s\n", strerror (errno));
_exit (EXIT_FAILURE);
}
}

/* Shortcut. If we are able to join the pause pid file, do it now so we don't
need to re-exec. */
xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR");
Expand Down Expand Up @@ -635,6 +663,12 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
for (f = 3; f <= open_files_max_fd; f++)
if (is_fd_inherited (f))
close (f);
if (do_socket_activation)
{
unsetenv ("LISTEN_PID");
unsetenv ("LISTEN_FDS");
unsetenv ("LISTEN_FDNAMES");
}

return pid;
}
Expand All @@ -660,6 +694,15 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
_exit (EXIT_FAILURE);
}

if (do_socket_activation)
{
char s[32];
sprintf (s, "%d", getpid());
setenv ("LISTEN_PID", s, true);
setenv ("LISTEN_FDS", saved_systemd_listen_fds, true);
setenv ("LISTEN_FDNAMES", saved_systemd_listen_fdnames, true);
}

setenv ("_CONTAINERS_USERNS_CONFIGURED", "init", 1);
setenv ("_CONTAINERS_ROOTLESS_UID", uid, 1);
setenv ("_CONTAINERS_ROOTLESS_GID", gid, 1);
Expand Down Expand Up @@ -777,9 +820,6 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
char **argv;
char uid[16];
char gid[16];
char *listen_fds = NULL;
char *listen_pid = NULL;
bool do_socket_activation = false;
char *cwd = getcwd (NULL, 0);
sigset_t sigset, oldsigset;

Expand All @@ -789,14 +829,6 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
_exit (EXIT_FAILURE);
}

listen_pid = getenv("LISTEN_PID");
listen_fds = getenv("LISTEN_FDS");

if (listen_pid != NULL && listen_fds != NULL)
{
if (strtol(listen_pid, NULL, 10) == getpid())
do_socket_activation = true;
}

sprintf (uid, "%d", geteuid ());
sprintf (gid, "%d", getegid ());
Expand All @@ -814,7 +846,7 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
{
long num_fds;

num_fds = strtol (listen_fds, NULL, 10);
num_fds = strtol (saved_systemd_listen_fds, NULL, 10);
if (num_fds != LONG_MIN && num_fds != LONG_MAX)
{
int f;
Expand Down Expand Up @@ -863,6 +895,8 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
char s[32];
sprintf (s, "%d", getpid());
setenv ("LISTEN_PID", s, true);
setenv ("LISTEN_FDS", saved_systemd_listen_fds, true);
setenv ("LISTEN_FDNAMES", saved_systemd_listen_fdnames, true);
}

setenv ("_CONTAINERS_USERNS_CONFIGURED", "init", 1);
Expand Down
103 changes: 103 additions & 0 deletions test/system/270-socket-activation.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env bats -*- bats -*-
#
# Tests podman system service under systemd socket activation
#

load helpers

SERVICE_NAME="podman_test_$(random_string)"

SYSTEMCTL="systemctl"
UNIT_DIR="/usr/lib/systemd/system"
SERVICE_SOCK_ADDR="/run/podman/podman.sock"

if is_rootless; then
UNIT_DIR="$HOME/.config/systemd/user"
mkdir -p $UNIT_DIR

SYSTEMCTL="$SYSTEMCTL --user"
if [ -z "$XDG_RUNTIME_DIR" ]; then
export XDG_RUNTIME_DIR=/run/user/$(id -u)
fi
SERVICE_SOCK_ADDR="$XDG_RUNTIME_DIR/podman/podman.sock"
fi

SERVICE_FILE="$UNIT_DIR/$SERVICE_NAME.service"
SOCKET_FILE="$UNIT_DIR/$SERVICE_NAME.socket"


function setup() {
skip_if_remote "systemd tests are meaningless over remote"

basic_setup

cat > $SERVICE_FILE <<EOF
[Unit]
Description=Podman API Service
Requires=podman.socket
After=podman.socket
Documentation=man:podman-system-service(1)
StartLimitIntervalSec=0
[Service]
Type=exec
KillMode=process
Environment=LOGGING="--log-level=info"
ExecStart=$PODMAN $LOGGING system service -t 2
EOF
cat > $SOCKET_FILE <<EOF
[Unit]
Description=Podman API Socket
Documentation=man:podman-system-service(1)
[Socket]
ListenStream=%t/podman/podman.sock
SocketMode=0660
[Install]
WantedBy=sockets.target
EOF

# ensure pause die before each test runs
if is_rootless; then
local pause_pid="$XDG_RUNTIME_DIR/libpod/tmp/pause.pid"
if [ -f $pause_pid ]; then
kill -9 $(cat $pause_pid) 2> /dev/null
rm -f $pause_pid
fi
fi
$SYSTEMCTL start "$SERVICE_NAME.socket"
}

function teardown() {
$SYSTEMCTL stop "$SERVICE_NAME.socket"
rm -f "$SERVICE_FILE" "$SOCKET_FILE"
$SYSTEMCTL daemon-reload
basic_teardown
}

@test "podman system service - socket activation - no container" {
run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping
is "$output" "OK" "podman service responses normally"
}

@test "podman system service - socket activation - exist container " {
run_podman run $IMAGE sleep 90
run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping
is "$output" "OK" "podman service responses normally"
}

@test "podman system service - socket activation - kill rootless pause " {
if ! is_rootless; then
skip "root podman no need pause process"
fi
run_podman run $IMAGE sleep 90
local pause_pid="$XDG_RUNTIME_DIR/libpod/tmp/pause.pid"
if [ -f $pause_pid ]; then
kill -9 $(cat $pause_pid) 2> /dev/null
fi
run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping
is "$output" "OK" "podman service responses normally"
}

# vim: filetype=sh

0 comments on commit 1c8d3d0

Please sign in to comment.